]> git.neil.brown.name Git - LaFS.git/commitdiff
use little-endian bit operations for inode usage map.
authorNeilBrown <neilb@suse.de>
Sat, 2 Oct 2010 01:46:04 +0000 (11:46 +1000)
committerNeilBrown <neilb@suse.de>
Sun, 10 Oct 2010 23:33:54 +0000 (10:33 +1100)
Must not use hos-endian here, so use generic 'le' operations.
Also protect all operations with i_mutex.  Even if the bitops
were atomic, we need the locking when punching a hole in the file,
or adding a new block.

Signed-off-by: NeilBrown <neilb@suse.de>
inode.c

diff --git a/inode.c b/inode.c
index c70a934553dfc47ef6c91394ef0b0c78ff58f891..1a117433c6cd8e771ebf6ff8fda05f5c2ef73e45 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -1409,13 +1409,13 @@ retry:
        buf = map_dblock(b);
        while (bnum == 0 && bit < 16) {
                /* Never return an inum below 16 - they are special */
-               if (!test_bit(bit, (unsigned long *)buf))
-                       set_bit(bit, (unsigned long *)buf);
+               if (!generic_test_le_bit(bit, (unsigned long *)buf))
+                       generic___clear_le_bit(bit, (unsigned long *)buf);
                bit++;
        }
 
-       bit = find_next_bit((unsigned long *)buf,
-                           fs->blocksize<<3, bit);
+       bit = generic_find_next_le_bit((unsigned long *)buf,
+                                      fs->blocksize<<3, bit);
        unmap_dblock(b, buf);
        LAFSI(im)->md.inodemap.nextbit = bit+1;
        if (bit >= fs->blocksize<<3) {
@@ -1500,12 +1500,13 @@ inode_map_new_commit(struct inode_map_new_info *imni)
                int blksize = imni->ib->b.inode->i_sb->s_blocksize;
                int bit = imni->ib->b.fileaddr & (blksize*8 - 1);
                int hole = 0;
-               struct inode *ino;
+               struct inode *ino = imni->mb->b.inode;
 
+               mutex_lock_nested(&ino->i_mutex, I_MUTEX_QUOTA);
                buf = map_dblock(imni->mb);
-               clear_bit(bit, buf);
+               generic___clear_le_bit(bit, buf);
                if (buf[blksize/sizeof(*buf)-1] == 0 &&
-                   find_first_bit(buf, blksize*8) == blksize*8)
+                   generic_find_next_le_bit(buf, blksize*8, 0) == blksize*8)
                        /* block is empty, punch a hole */
                        hole = 1;
 
@@ -1515,8 +1516,8 @@ inode_map_new_commit(struct inode_map_new_info *imni)
                else
                        lafs_dirty_dblock(imni->mb);
 
-               ino = imni->mb->b.inode;
                putdref(imni->mb, MKREF(cfi_map));
+               mutex_unlock(&ino->i_mutex);
                iput(ino);
        }
        putdref(imni->ib, MKREF(cfi_ino));
@@ -1622,17 +1623,21 @@ static int inode_map_free(struct fs *fs, struct super_block *sb, u32 inum)
        u32 bnum;
        int err;
 
+       mutex_lock_nested(&im->i_mutex, I_MUTEX_QUOTA);
+
        bnum = inum >> (3 + sb->s_blocksize_bits);
        bit = inum - (bnum << (3 + sb->s_blocksize_bits));
        b = lafs_get_block(im, bnum, NULL, GFP_KERNEL, MKREF(inode_map_free));
        if (!b) {
+               mutex_unlock(&im->i_mutex);
                iput(im);
                return -ENOMEM;
        }
        err = lafs_read_block(b);
        if (err) {
-               iput(im);
                putdref(b, MKREF(inode_map_free));
+               mutex_unlock(&im->i_mutex);
+               iput(im);
                return err;
        }
        lafs_iolock_written(&b->b);
@@ -1647,11 +1652,12 @@ retry:
        }
        BUG_ON(err < 0);
        buf = map_dblock(b);
-       set_bit(bit, buf); // FIXME this is host-endian !!
+       generic___set_le_bit(bit, buf);
        unmap_dblock(b, buf);
        lafs_dirty_dblock(b);
        putdref(b, MKREF(inode_map_free));
        lafs_checkpoint_unlock(fs);
+               mutex_unlock(&im->i_mutex);
        iput(im);
        return 0;
 }