static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, struct inode *inode) { struct nilfs_sb_info *sbi = NILFS_SB(sb); struct inode *dat = nilfs_dat_inode(sbi->s_nilfs); struct buffer_head *bh; struct nilfs_inode *raw_inode; int err; down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ err = nilfs_ifile_get_inode_block(sbi->s_ifile, ino, &bh); if (unlikely(err)) goto bad_inode; raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); #ifdef CONFIG_NILFS_FS_POSIX_ACL ii->i_acl = NILFS_ACL_NOT_CACHED; ii->i_default_acl = NILFS_ACL_NOT_CACHED; #endif if (nilfs_read_inode_common(inode, raw_inode)) goto failed_unmap; if (S_ISREG(inode->i_mode)) { inode->i_op = &nilfs_file_inode_operations; inode->i_fop = &nilfs_file_operations; inode->i_mapping->a_ops = &nilfs_aops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &nilfs_dir_inode_operations; inode->i_fop = &nilfs_dir_operations; inode->i_mapping->a_ops = &nilfs_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &nilfs_symlink_inode_operations; inode->i_mapping->a_ops = &nilfs_aops; } else { inode->i_op = &nilfs_special_inode_operations; init_special_inode( inode, inode->i_mode, new_decode_dev(le64_to_cpu(raw_inode->i_device_code))); } nilfs_ifile_unmap_inode(sbi->s_ifile, ino, bh); brelse(bh); up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ nilfs_set_inode_flags(inode); return 0; failed_unmap: nilfs_ifile_unmap_inode(sbi->s_ifile, ino, bh); brelse(bh); bad_inode: up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ return err; }
int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, sector_t pblocknr, struct buffer_head **pbh) { struct buffer_head *bh; struct inode *inode = NILFS_BTNC_I(btnc); int err; bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node); if (unlikely(!bh)) return -ENOMEM; err = -EEXIST; /* internal code */ if (buffer_uptodate(bh) || buffer_dirty(bh)) goto found; if (pblocknr == 0) { pblocknr = blocknr; if (inode->i_ino != NILFS_DAT_INO) { struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); /* blocknr is a virtual block number */ err = nilfs_dat_translate(dat, blocknr, &pblocknr); if (unlikely(err)) { brelse(bh); goto out_locked; } } } lock_buffer(bh); if (buffer_uptodate(bh)) { unlock_buffer(bh); err = -EEXIST; /* internal code */ goto found; } set_buffer_mapped(bh); bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev; bh->b_blocknr = pblocknr; /* set block address for read */ bh->b_end_io = end_buffer_read_sync; get_bh(bh); submit_bh(READ, bh); bh->b_blocknr = blocknr; /* set back to the given block address */ err = 0; found: *pbh = bh; out_locked: unlock_page(bh->b_page); page_cache_release(bh->b_page); return err; }
struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) { return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); }
int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, sector_t pblocknr, struct buffer_head **pbh, int newblk) { struct buffer_head *bh; struct inode *inode = NILFS_BTNC_I(btnc); int err; btnode_debug(3, "called: blocknr=%llu pblocknr=%llu new=%d ino=%lu\n", (unsigned long long)blocknr, (unsigned long long)pblocknr, newblk, inode->i_ino); bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node); if (unlikely(!bh)) return -ENOMEM; err = -EEXIST; /* internal code */ if (newblk) { if (unlikely(buffer_mapped(bh) || buffer_uptodate(bh) || buffer_dirty(bh))) { BH_DEBUG(bh, "invalid new bh"); BUG(); } bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev; bh->b_blocknr = blocknr; set_buffer_mapped(bh); set_buffer_uptodate(bh); goto found; } if (buffer_uptodate(bh) || buffer_dirty(bh)) goto found; if (pblocknr == 0) { pblocknr = blocknr; if (inode->i_ino != NILFS_DAT_INO) { struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); /* blocknr is a virtual block number */ err = nilfs_dat_translate(dat, blocknr, &pblocknr); if (unlikely(err)) { brelse(bh); btnode_debug(1, "return %d (xlate).\n", err); goto out_locked; } } } lock_buffer(bh); if (buffer_uptodate(bh)) { unlock_buffer(bh); err = -EEXIST; /* internal code */ goto found; } set_buffer_mapped(bh); bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev; bh->b_blocknr = pblocknr; /* set block address for read */ bh->b_end_io = end_buffer_read_sync; get_bh(bh); submit_bh(READ, bh); bh->b_blocknr = blocknr; /* set back to the given block address */ err = 0; found: *pbh = bh; out_locked: unlock_page(bh->b_page); page_cache_release(bh->b_page); btnode_debug(3, "done (err=%d)\n", err); return err; }
/** * nilfs_get_block() - get a file block on the filesystem (callback function) * @inode - inode struct of the target file * @blkoff - file block number * @bh_result - buffer head to be mapped on * @create - indicate whether allocating the block or not when it has not * been allocated yet. * * This function does not issue actual read request of the specified data * block. It is done by VFS. */ int nilfs_get_block(struct inode *inode, sector_t blkoff, struct buffer_head *bh_result, int create) { struct nilfs_inode_info *ii = NILFS_I(inode); __u64 blknum = 0; int err = 0, ret; struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; down_read(&NILFS_MDT(dat)->mi_sem); ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); up_read(&NILFS_MDT(dat)->mi_sem); if (ret >= 0) { /* found */ map_bh(bh_result, inode->i_sb, blknum); if (ret > 0) bh_result->b_size = (ret << inode->i_blkbits); goto out; } /* data block was not found */ if (ret == -ENOENT && create) { struct nilfs_transaction_info ti; bh_result->b_blocknr = 0; err = nilfs_transaction_begin(inode->i_sb, &ti, 1); if (unlikely(err)) goto out; err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, (unsigned long)bh_result); if (unlikely(err != 0)) { if (err == -EEXIST) { /* * The get_block() function could be called * from multiple callers for an inode. * However, the page having this block must * be locked in this case. */ printk(KERN_WARNING "nilfs_get_block: a race condition " "while inserting a data block. " "(inode number=%lu, file block " "offset=%llu)\n", inode->i_ino, (unsigned long long)blkoff); err = 0; } else if (err == -EINVAL) { nilfs_error(inode->i_sb, __func__, "broken bmap (inode=%lu)\n", inode->i_ino); err = -EIO; } nilfs_transaction_abort(inode->i_sb); goto out; } nilfs_transaction_commit(inode->i_sb); /* never fails */ /* Error handling should be detailed */ set_buffer_new(bh_result); map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed to proper value */ } else if (ret == -ENOENT) { /* not found is not error (e.g. hole); must return without the mapped state flag. */ ; } else { err = ret; } out: return err; }