]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nilfs2/inode.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / fs / nilfs2 / inode.c
index 71d4bc8464e09b793b6c4eb23b97ff09ee093002..2fd440d8d6b8d9b2b469c2aaec757bca05a9ac58 100644 (file)
@@ -58,7 +58,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
        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));
+       struct inode *dat = NILFS_I_NILFS(inode)->ns_dat;
        unsigned maxblocks = bh_result->b_size >> inode->i_blkbits;
 
        down_read(&NILFS_MDT(dat)->mi_sem);
@@ -96,11 +96,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                                       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;
@@ -109,6 +104,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                nilfs_transaction_commit(inode->i_sb); /* never fails */
                /* Error handling should be detailed */
                set_buffer_new(bh_result);
+               set_buffer_delay(bh_result);
                map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed
                                                      to proper value */
        } else if (ret == -ENOENT) {
@@ -185,10 +181,9 @@ static int nilfs_set_page_dirty(struct page *page)
 
        if (ret) {
                struct inode *inode = page->mapping->host;
-               struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
                unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits);
 
-               nilfs_set_file_dirty(sbi, inode, nr_dirty);
+               nilfs_set_file_dirty(inode, nr_dirty);
        }
        return ret;
 }
@@ -229,7 +224,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping,
                                                  start + copied);
        copied = generic_write_end(file, mapping, pos, len, copied, page,
                                   fsdata);
-       nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty);
+       nilfs_set_file_dirty(inode, nr_dirty);
        err = nilfs_transaction_commit(inode->i_sb);
        return err ? : copied;
 }
@@ -425,13 +420,12 @@ static int __nilfs_read_inode(struct super_block *sb,
                              struct nilfs_root *root, unsigned long ino,
                              struct inode *inode)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct inode *dat = nilfs_dat_inode(sbi->s_nilfs);
+       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
        struct buffer_head *bh;
        struct nilfs_inode *raw_inode;
        int err;
 
-       down_read(&NILFS_MDT(dat)->mi_sem);     /* XXX */
+       down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh);
        if (unlikely(err))
                goto bad_inode;
@@ -461,7 +455,7 @@ static int __nilfs_read_inode(struct super_block *sb,
        }
        nilfs_ifile_unmap_inode(root->ifile, ino, bh);
        brelse(bh);
-       up_read(&NILFS_MDT(dat)->mi_sem);       /* XXX */
+       up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        nilfs_set_inode_flags(inode);
        return 0;
 
@@ -470,7 +464,7 @@ static int __nilfs_read_inode(struct super_block *sb,
        brelse(bh);
 
  bad_inode:
-       up_read(&NILFS_MDT(dat)->mi_sem);       /* XXX */
+       up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
        return err;
 }
 
@@ -629,7 +623,7 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,
 
        if (!test_bit(NILFS_I_BMAP, &ii->i_state))
                return;
- repeat:
+repeat:
        ret = nilfs_bmap_last_key(ii->i_bmap, &b);
        if (ret == -ENOENT)
                return;
@@ -646,14 +640,10 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,
                     nilfs_bmap_truncate(ii->i_bmap, b) == 0))
                goto repeat;
 
- failed:
-       if (ret == -EINVAL)
-               nilfs_error(ii->vfs_inode.i_sb, __func__,
-                           "bmap is broken (ino=%lu)", ii->vfs_inode.i_ino);
-       else
-               nilfs_warning(ii->vfs_inode.i_sb, __func__,
-                             "failed to truncate bmap (ino=%lu, err=%d)",
-                             ii->vfs_inode.i_ino, ret);
+failed:
+       nilfs_warning(ii->vfs_inode.i_sb, __func__,
+                     "failed to truncate bmap (ino=%lu, err=%d)",
+                     ii->vfs_inode.i_ino, ret);
 }
 
 void nilfs_truncate(struct inode *inode)
@@ -682,7 +672,7 @@ void nilfs_truncate(struct inode *inode)
                nilfs_set_transaction_flag(NILFS_TI_SYNC);
 
        nilfs_mark_inode_dirty(inode);
-       nilfs_set_file_dirty(NILFS_SB(sb), inode, 0);
+       nilfs_set_file_dirty(inode, 0);
        nilfs_transaction_commit(sb);
        /* May construct a logical segment and may fail in sync mode.
           But truncate has no return value. */
@@ -785,20 +775,24 @@ out_err:
        return err;
 }
 
-int nilfs_permission(struct inode *inode, int mask)
+int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       struct nilfs_root *root = NILFS_I(inode)->i_root;
+       struct nilfs_root *root;
 
+       if (flags & IPERM_FLAG_RCU)
+               return -ECHILD;
+
+       root = NILFS_I(inode)->i_root;
        if ((mask & MAY_WRITE) && root &&
            root->cno != NILFS_CPTREE_CURRENT_CNO)
                return -EROFS; /* snapshot is not writable */
 
-       return generic_permission(inode, mask, NULL);
+       return generic_permission(inode, mask, flags, NULL);
 }
 
-int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
-                          struct buffer_head **pbh)
+int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh)
 {
+       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct nilfs_inode_info *ii = NILFS_I(inode);
        int err;
 
@@ -839,9 +833,9 @@ int nilfs_inode_dirty(struct inode *inode)
        return ret;
 }
 
-int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode,
-                        unsigned nr_dirty)
+int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
 {
+       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct nilfs_inode_info *ii = NILFS_I(inode);
 
        atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks);
@@ -874,11 +868,10 @@ int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode,
 
 int nilfs_mark_inode_dirty(struct inode *inode)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct buffer_head *ibh;
        int err;
 
-       err = nilfs_load_inode_block(sbi, inode, &ibh);
+       err = nilfs_load_inode_block(inode, &ibh);
        if (unlikely(err)) {
                nilfs_warning(inode->i_sb, __func__,
                              "failed to reget inode block.\n");
@@ -920,3 +913,134 @@ void nilfs_dirty_inode(struct inode *inode)
        nilfs_mark_inode_dirty(inode);
        nilfs_transaction_commit(inode->i_sb); /* never fails */
 }
+
+int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                __u64 start, __u64 len)
+{
+       struct the_nilfs *nilfs = NILFS_I_NILFS(inode);
+       __u64 logical = 0, phys = 0, size = 0;
+       __u32 flags = 0;
+       loff_t isize;
+       sector_t blkoff, end_blkoff;
+       sector_t delalloc_blkoff;
+       unsigned long delalloc_blklen;
+       unsigned int blkbits = inode->i_blkbits;
+       int ret, n;
+
+       ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+       if (ret)
+               return ret;
+
+       mutex_lock(&inode->i_mutex);
+
+       isize = i_size_read(inode);
+
+       blkoff = start >> blkbits;
+       end_blkoff = (start + len - 1) >> blkbits;
+
+       delalloc_blklen = nilfs_find_uncommitted_extent(inode, blkoff,
+                                                       &delalloc_blkoff);
+
+       do {
+               __u64 blkphy;
+               unsigned int maxblocks;
+
+               if (delalloc_blklen && blkoff == delalloc_blkoff) {
+                       if (size) {
+                               /* End of the current extent */
+                               ret = fiemap_fill_next_extent(
+                                       fieinfo, logical, phys, size, flags);
+                               if (ret)
+                                       break;
+                       }
+                       if (blkoff > end_blkoff)
+                               break;
+
+                       flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_DELALLOC;
+                       logical = blkoff << blkbits;
+                       phys = 0;
+                       size = delalloc_blklen << blkbits;
+
+                       blkoff = delalloc_blkoff + delalloc_blklen;
+                       delalloc_blklen = nilfs_find_uncommitted_extent(
+                               inode, blkoff, &delalloc_blkoff);
+                       continue;
+               }
+
+               /*
+                * Limit the number of blocks that we look up so as
+                * not to get into the next delayed allocation extent.
+                */
+               maxblocks = INT_MAX;
+               if (delalloc_blklen)
+                       maxblocks = min_t(sector_t, delalloc_blkoff - blkoff,
+                                         maxblocks);
+               blkphy = 0;
+
+               down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
+               n = nilfs_bmap_lookup_contig(
+                       NILFS_I(inode)->i_bmap, blkoff, &blkphy, maxblocks);
+               up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
+
+               if (n < 0) {
+                       int past_eof;
+
+                       if (unlikely(n != -ENOENT))
+                               break; /* error */
+
+                       /* HOLE */
+                       blkoff++;
+                       past_eof = ((blkoff << blkbits) >= isize);
+
+                       if (size) {
+                               /* End of the current extent */
+
+                               if (past_eof)
+                                       flags |= FIEMAP_EXTENT_LAST;
+
+                               ret = fiemap_fill_next_extent(
+                                       fieinfo, logical, phys, size, flags);
+                               if (ret)
+                                       break;
+                               size = 0;
+                       }
+                       if (blkoff > end_blkoff || past_eof)
+                               break;
+               } else {
+                       if (size) {
+                               if (phys && blkphy << blkbits == phys + size) {
+                                       /* The current extent goes on */
+                                       size += n << blkbits;
+                               } else {
+                                       /* Terminate the current extent */
+                                       ret = fiemap_fill_next_extent(
+                                               fieinfo, logical, phys, size,
+                                               flags);
+                                       if (ret || blkoff > end_blkoff)
+                                               break;
+
+                                       /* Start another extent */
+                                       flags = FIEMAP_EXTENT_MERGED;
+                                       logical = blkoff << blkbits;
+                                       phys = blkphy << blkbits;
+                                       size = n << blkbits;
+                               }
+                       } else {
+                               /* Start a new extent */
+                               flags = FIEMAP_EXTENT_MERGED;
+                               logical = blkoff << blkbits;
+                               phys = blkphy << blkbits;
+                               size = n << blkbits;
+                       }
+                       blkoff += n;
+               }
+               cond_resched();
+       } while (true);
+
+       /* If ret is 1 then we just hit the end of the extent array */
+       if (ret == 1)
+               ret = 0;
+
+       mutex_unlock(&inode->i_mutex);
+       return ret;
+}