]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/ufs/inode.c
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / fs / ufs / inode.c
index 7e41aee7b69a660914e7cb26765714746929a306..9f4590261134085cbabcea1ee9a72382239ba479 100644 (file)
@@ -235,7 +235,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to,
 
        p = ufs_get_direct_data_ptr(uspi, ufsi, block);
        tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
-                               new_size, err, locked_page);
+                               new_size - (lastfrag & uspi->s_fpbmask), err,
+                               locked_page);
        return tmp != 0;
 }
 
@@ -284,7 +285,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
                        goal += uspi->s_fpb;
        }
        tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
-                               goal, uspi->s_fpb, err, locked_page);
+                               goal, nfrags, err, locked_page);
 
        if (!tmp) {
                *err = -ENOSPC;
@@ -400,11 +401,20 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff
        u64 phys64 = 0;
        unsigned frag = fragment & uspi->s_fpbmask;
 
-       if (!create) {
-               phys64 = ufs_frag_map(inode, offsets, depth);
-               goto out;
-       }
+       phys64 = ufs_frag_map(inode, offsets, depth);
+       if (!create)
+               goto done;
 
+       if (phys64) {
+               if (fragment >= UFS_NDIR_FRAGMENT)
+                       goto done;
+               read_seqlock_excl(&UFS_I(inode)->meta_lock);
+               if (fragment < UFS_I(inode)->i_lastfrag) {
+                       read_sequnlock_excl(&UFS_I(inode)->meta_lock);
+                       goto done;
+               }
+               read_sequnlock_excl(&UFS_I(inode)->meta_lock);
+       }
         /* This code entered only while writing ....? */
 
        mutex_lock(&UFS_I(inode)->truncate_mutex);
@@ -448,6 +458,11 @@ out:
        }
        mutex_unlock(&UFS_I(inode)->truncate_mutex);
        return err;
+
+done:
+       if (phys64)
+               map_bh(bh_result, sb, phys64 + frag);
+       return 0;
 }
 
 static int ufs_writepage(struct page *page, struct writeback_control *wbc)
@@ -841,8 +856,11 @@ void ufs_evict_inode(struct inode * inode)
        truncate_inode_pages_final(&inode->i_data);
        if (want_delete) {
                inode->i_size = 0;
-               if (inode->i_blocks)
+               if (inode->i_blocks &&
+                   (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                    S_ISLNK(inode->i_mode)))
                        ufs_truncate_blocks(inode);
+               ufs_update_inode(inode, inode_needs_sync(inode));
        }
 
        invalidate_inode_buffers(inode);
@@ -868,7 +886,6 @@ static inline void free_data(struct to_free *ctx, u64 from, unsigned count)
        ctx->to = from + count;
 }
 
-#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
 #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
 
 static void ufs_trunc_direct(struct inode *inode)
@@ -1100,25 +1117,30 @@ out:
        return err;
 }
 
-static void __ufs_truncate_blocks(struct inode *inode)
+static void ufs_truncate_blocks(struct inode *inode)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
        struct super_block *sb = inode->i_sb;
        struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
        unsigned offsets[4];
-       int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets);
+       int depth;
        int depth2;
        unsigned i;
        struct ufs_buffer_head *ubh[3];
        void *p;
        u64 block;
 
-       if (!depth)
-               return;
+       if (inode->i_size) {
+               sector_t last = (inode->i_size - 1) >> uspi->s_bshift;
+               depth = ufs_block_to_path(inode, last, offsets);
+               if (!depth)
+                       return;
+       } else {
+               depth = 1;
+       }
 
-       /* find the last non-zero in offsets[] */
        for (depth2 = depth - 1; depth2; depth2--)
-               if (offsets[depth2])
+               if (offsets[depth2] != uspi->s_apb - 1)
                        break;
 
        mutex_lock(&ufsi->truncate_mutex);
@@ -1127,9 +1149,8 @@ static void __ufs_truncate_blocks(struct inode *inode)
                offsets[0] = UFS_IND_BLOCK;
        } else {
                /* get the blocks that should be partially emptied */
-               p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]);
+               p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++);
                for (i = 0; i < depth2; i++) {
-                       offsets[i]++;   /* next branch is fully freed */
                        block = ufs_data_ptr_to_cpu(sb, p);
                        if (!block)
                                break;
@@ -1140,7 +1161,7 @@ static void __ufs_truncate_blocks(struct inode *inode)
                                write_sequnlock(&ufsi->meta_lock);
                                break;
                        }
-                       p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]);
+                       p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]++);
                }
                while (i--)
                        free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1);
@@ -1155,7 +1176,9 @@ static void __ufs_truncate_blocks(struct inode *inode)
                        free_full_branch(inode, block, i - UFS_IND_BLOCK + 1);
                }
        }
+       read_seqlock_excl(&ufsi->meta_lock);
        ufsi->i_lastfrag = DIRECT_FRAGMENT;
+       read_sequnlock_excl(&ufsi->meta_lock);
        mark_inode_dirty(inode);
        mutex_unlock(&ufsi->truncate_mutex);
 }
@@ -1183,7 +1206,7 @@ static int ufs_truncate(struct inode *inode, loff_t size)
 
        truncate_setsize(inode, size);
 
-       __ufs_truncate_blocks(inode);
+       ufs_truncate_blocks(inode);
        inode->i_mtime = inode->i_ctime = current_time(inode);
        mark_inode_dirty(inode);
 out:
@@ -1191,16 +1214,6 @@ out:
        return err;
 }
 
-static void ufs_truncate_blocks(struct inode *inode)
-{
-       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-             S_ISLNK(inode->i_mode)))
-               return;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return;
-       __ufs_truncate_blocks(inode);
-}
-
 int ufs_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = d_inode(dentry);