/** * nilfs_compute_checksum - compute checksum of blocks continuously * @nilfs: nilfs object * @bhs: buffer head of start block * @sum: place to store result * @offset: offset bytes in the first block * @check_bytes: number of bytes to be checked * @start: DBN of start block * @nblock: number of blocks to be checked */ static int nilfs_compute_checksum(struct the_nilfs *nilfs, struct buffer_head *bhs, u32 *sum, unsigned long offset, u64 check_bytes, sector_t start, unsigned long nblock) { unsigned int blocksize = nilfs->ns_blocksize; unsigned long size; u32 crc; BUG_ON(offset >= blocksize); check_bytes -= offset; size = min_t(u64, check_bytes, blocksize - offset); crc = crc32_le(nilfs->ns_crc_seed, (unsigned char *)bhs->b_data + offset, size); if (--nblock > 0) { do { struct buffer_head *bh; bh = __bread(nilfs->ns_bdev, ++start, blocksize); if (!bh) return -EIO; check_bytes -= size; size = min_t(u64, check_bytes, blocksize); crc = crc32_le(crc, bh->b_data, size); brelse(bh); } while (--nblock > 0); } *sum = crc; return 0; }
s32 bdev_read(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 num_secs, s32 read) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); #ifdef CONFIG_EXFAT_KERNEL_DEBUG struct exfat_sb_info *sbi = EXFAT_SB(sb); long flags = sbi->debug_flags; if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) return FFS_MEDIAERR; #endif /* CONFIG_EXFAT_KERNEL_DEBUG */ if (!p_bd->opened) return FFS_MEDIAERR; if (*bh) __brelse(*bh); if (read) *bh = __bread(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); else *bh = __getblk(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); if (*bh) return FFS_SUCCESS; WARN(!p_fs->dev_ejected, "[EXFAT] No bh, device seems wrong or to be ejected.\n"); return FFS_MEDIAERR; }
/** * nilfs_read_log_header - read summary header of the specified log * @nilfs: nilfs object * @start_blocknr: start block number of the log * @sum: pointer to return segment summary structure */ static struct buffer_head * nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr, struct nilfs_segment_summary **sum) { struct buffer_head *bh_sum; bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize); if (bh_sum) *sum = (struct nilfs_segment_summary *)bh_sum->b_data; return bh_sum; }
static int bdev_read_page(struct block_device *bdev, long pos, void *buf) { struct buffer_head *bh; BUG_ON (pos%PAGE_SIZE); bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE); if (!bh || (!bh->b_data)) { return -1; } memcpy(buf, bh->b_data, PAGE_SIZE); /* FIXME: may need kmap() */ BUG_ON(!buffer_uptodate(bh)); brelse(bh); return 0; }
static int nilfs_recovery_copy_block(struct the_nilfs *nilfs, struct nilfs_recovery_block *rb, struct page *page) { struct buffer_head *bh_org; void *kaddr; bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize); if (unlikely(!bh_org)) return -EIO; kaddr = kmap_atomic(page); memcpy(kaddr + bh_offset(bh_org), bh_org->b_data, bh_org->b_size); kunmap_atomic(kaddr); brelse(bh_org); return 0; }
/** * nilfs_read_super_root_block - read super root block * @nilfs: nilfs object * @sr_block: disk block number of the super root block * @pbh: address of a buffer_head pointer to return super root buffer * @check: CRC check flag */ int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block, struct buffer_head **pbh, int check) { struct buffer_head *bh_sr; struct nilfs_super_root *sr; u32 crc; int ret; *pbh = NULL; bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize); if (unlikely(!bh_sr)) { ret = NILFS_SEG_FAIL_IO; goto failed; } sr = (struct nilfs_super_root *)bh_sr->b_data; if (check) { unsigned int bytes = le16_to_cpu(sr->sr_bytes); if (bytes == 0 || bytes > nilfs->ns_blocksize) { ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT; goto failed_bh; } if (nilfs_compute_checksum( nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes, sr_block, 1)) { ret = NILFS_SEG_FAIL_IO; goto failed_bh; } if (crc != le32_to_cpu(sr->sr_sum)) { ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT; goto failed_bh; } } *pbh = bh_sr; return 0; failed_bh: brelse(bh_sr); failed: return nilfs_warn_segment_error(nilfs->ns_sb, ret); }
/** * nilfs_read_summary_info - read an item on summary blocks of a log * @nilfs: nilfs object * @pbh: the current buffer head on summary blocks [in, out] * @offset: the current byte offset on summary blocks [in, out] * @bytes: byte size of the item to be read */ static void *nilfs_read_summary_info(struct the_nilfs *nilfs, struct buffer_head **pbh, unsigned int *offset, unsigned int bytes) { void *ptr; sector_t blocknr; BUG_ON((*pbh)->b_size < *offset); if (bytes > (*pbh)->b_size - *offset) { blocknr = (*pbh)->b_blocknr; brelse(*pbh); *pbh = __bread(nilfs->ns_bdev, blocknr + 1, nilfs->ns_blocksize); if (unlikely(!*pbh)) return NULL; *offset = 0; } ptr = (*pbh)->b_data + *offset; *offset += bytes; return ptr; }
static int bdev_write_page(struct block_device *bdev, long pos, void *buf) { #if 0 struct buffer_head *bh; BUG_ON (pos%PAGE_SIZE); bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE); if (!bh || (!bh->b_data)) { return -1; } memcpy(bh->b_data, buf, PAGE_SIZE); /* FIXME: may need kmap() */ BUG_ON(!buffer_uptodate(bh)); generic_make_request(WRITE, bh); if (!buffer_uptodate(bh)) printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unsuccessful...\n", name_resume, resume_file); wait_on_buffer(bh); brelse(bh); return 0; #endif printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unimplemented...\n", name_resume, resume_file); return 0; }
s32 bdev_mread(struct super_block *sb, u32 secno, struct buffer_head **bh, u32 num_secs, s32 read) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); u8 blksize_bits = sb->s_blocksize_bits; #ifdef CONFIG_SDFAT_DBG_IOCTL struct sdfat_sb_info *sbi = SDFAT_SB(sb); long flags = sbi->debug_flags; if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) return -EIO; #endif /* CONFIG_SDFAT_DBG_IOCTL */ if (!fsi->bd_opened) return -EIO; brelse(*bh); if (read) *bh = __bread(sb->s_bdev, secno, num_secs << blksize_bits); else *bh = __getblk(sb->s_bdev, secno, num_secs << blksize_bits); /* read successfully */ if (*bh) return 0; /* * patch 1.2.4 : reset ONCE warning message per volume. */ if(!(fsi->prev_eio & SDFAT_EIO_READ)) { fsi->prev_eio |= SDFAT_EIO_READ; sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); #ifdef CONFIG_SDFAT_DEBUG sdfat_debug_warn_on(1); #endif } return -EIO; }
/** * nilfs_skip_summary_info - skip items on summary blocks of a log * @nilfs: nilfs object * @pbh: the current buffer head on summary blocks [in, out] * @offset: the current byte offset on summary blocks [in, out] * @bytes: byte size of the item to be skipped * @count: number of items to be skipped */ static void nilfs_skip_summary_info(struct the_nilfs *nilfs, struct buffer_head **pbh, unsigned int *offset, unsigned int bytes, unsigned long count) { unsigned int rest_item_in_current_block = ((*pbh)->b_size - *offset) / bytes; if (count <= rest_item_in_current_block) { *offset += bytes * count; } else { sector_t blocknr = (*pbh)->b_blocknr; unsigned int nitem_per_block = (*pbh)->b_size / bytes; unsigned int bcnt; count -= rest_item_in_current_block; bcnt = DIV_ROUND_UP(count, nitem_per_block); *offset = bytes * (count - (bcnt - 1) * nitem_per_block); brelse(*pbh); *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt, nilfs->ns_blocksize); } }
/** * nilfs_scan_dsync_log - get block information of a log written for data sync * @nilfs: nilfs object * @start_blocknr: start block number of the log * @sum: log summary information * @head: list head to add nilfs_recovery_block struct */ static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr, struct nilfs_segment_summary *sum, struct list_head *head) { struct buffer_head *bh; unsigned int offset; u32 nfinfo, sumbytes; sector_t blocknr; ino_t ino; int err = -EIO; nfinfo = le32_to_cpu(sum->ss_nfinfo); if (!nfinfo) return 0; sumbytes = le32_to_cpu(sum->ss_sumbytes); blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize); bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize); if (unlikely(!bh)) goto out; offset = le16_to_cpu(sum->ss_bytes); for (;;) { unsigned long nblocks, ndatablk, nnodeblk; struct nilfs_finfo *finfo; finfo = nilfs_read_summary_info(nilfs, &bh, &offset, sizeof(*finfo)); if (unlikely(!finfo)) goto out; ino = le64_to_cpu(finfo->fi_ino); nblocks = le32_to_cpu(finfo->fi_nblocks); ndatablk = le32_to_cpu(finfo->fi_ndatablk); nnodeblk = nblocks - ndatablk; while (ndatablk-- > 0) { struct nilfs_recovery_block *rb; struct nilfs_binfo_v *binfo; binfo = nilfs_read_summary_info(nilfs, &bh, &offset, sizeof(*binfo)); if (unlikely(!binfo)) goto out; rb = kmalloc(sizeof(*rb), GFP_NOFS); if (unlikely(!rb)) { err = -ENOMEM; goto out; } rb->ino = ino; rb->blocknr = blocknr++; rb->vblocknr = le64_to_cpu(binfo->bi_vblocknr); rb->blkoff = le64_to_cpu(binfo->bi_blkoff); /* INIT_LIST_HEAD(&rb->list); */ list_add_tail(&rb->list, head); } if (--nfinfo == 0) break; blocknr += nnodeblk; /* always 0 for data sync logs */ nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64), nnodeblk); if (unlikely(!bh)) goto out; } err = 0; out: brelse(bh); /* brelse(NULL) is just ignored */ return err; }
/****************************************************************************** * * axfs_get_sb_block * * Description: * Populates a axfs_fill_super_info struct after sanity checking the * block device * * Parameters: * (IN) fs_type - pointer to file_system_type * * (IN) flags - mount flags * * (IN) dev_name - block device name passed in from mount * * (IN) secondary_blk_dev - block device name enter from mount -o * * Returns: * pointer to a axfs_file_super_info or an error pointer * *****************************************************************************/ static struct axfs_fill_super_info *axfs_get_sb_block(struct file_system_type *fs_type, int flags, const char *dev_name, char *secondary_blk_dev) { struct nameidata nd; struct buffer_head *bh = NULL; struct axfs_fill_super_info *output; struct block_device *bdev = NULL; int err; err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); if (err) return ERR_PTR(-EINVAL); if (secondary_blk_dev) { printk(KERN_ERR "axfs: can't mount 2 block device's \"%s\" and \"%s\"\n", dev_name, secondary_blk_dev); err = -EINVAL; goto path_out; } if (!S_ISBLK(nd.path.dentry->d_inode->i_mode)) { err = -EINVAL; goto path_out; } if (nd.path.mnt->mnt_flags & MNT_NODEV) { err = -EACCES; goto path_out; } bdev = open_bdev_exclusive(dev_name, flags, fs_type); if (IS_ERR(bdev)){ err = PTR_ERR(bdev); goto path_out; } bh = __bread(bdev, 0, bdev->bd_block_size); if (!bh) { err = -EIO; goto out; } output = (struct axfs_fill_super_info *)vmalloc(sizeof(struct axfs_fill_super_info)); if(!output) { err = -ENOMEM; goto out; } output->onmedia_super_block = (struct axfs_super_onmedia *)vmalloc(sizeof(struct axfs_super_onmedia)); if(!output->onmedia_super_block) { err = -ENOMEM; goto out; } memcpy((char *)output->onmedia_super_block, bh->b_data, sizeof(struct axfs_super_onmedia)); if(IS_ERR(output)) { err = PTR_ERR(output); goto out; } output->physical_start_address = 0; output->virtual_start_address = 0; path_put(&nd.path); close_bdev_exclusive(bdev, flags); free_buffer_head(bh); return output; out: close_bdev_exclusive(bdev,flags); if (bh) { free_buffer_head(bh); } path_out: path_put(&nd.path); printk(KERN_NOTICE "axfs_get_sb_block(): Invalid device \"%s\"\n", dev_name); return ERR_PTR(err); }