Merge http://sucs.org/~rohan/git/gfs2-3.0-nmw
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 17:44:50 +0000 (10:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 17:44:50 +0000 (10:44 -0700)
* http://sucs.org/~rohan/git/gfs2-3.0-nmw: (24 commits)
  GFS2: Move readahead of metadata during deallocation into its own function
  GFS2: Remove two unused variables
  GFS2: Misc fixes
  GFS2: rewrite fallocate code to write blocks directly
  GFS2: speed up delete/unlink performance for large files
  GFS2: Fix off-by-one in gfs2_blk2rgrpd
  GFS2: Clean up ->page_mkwrite
  GFS2: Correctly set goal block after allocation
  GFS2: Fix AIL flush issue during fsync
  GFS2: Use cached rgrp in gfs2_rlist_add()
  GFS2: Call do_strip() directly from recursive_scan()
  GFS2: Remove obsolete assert
  GFS2: Cache the most recently used resource group in the inode
  GFS2: Make resource groups "append only" during life of fs
  GFS2: Use rbtree for resource groups and clean up bitmap buffer ref count scheme
  GFS2: Fix lseek after SEEK_DATA, SEEK_HOLE have been added
  GFS2: Clean up gfs2_create
  GFS2: Use ->dirty_inode()
  GFS2: Fix bug trap and journaled data fsync
  GFS2: Fix inode allocation error path
  ...

19 files changed:
fs/gfs2/acl.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/dir.c
fs/gfs2/file.c
fs/gfs2/glops.c
fs/gfs2/glops.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/lops.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/trans.c
fs/gfs2/trans.h
fs/gfs2/xattr.c

index 34501b6..65978d7 100644 (file)
@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
                iattr.ia_valid = ATTR_MODE;
                iattr.ia_mode = mode;
 
-               error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
+               error = gfs2_setattr_simple(inode, &iattr);
        }
 
        return error;
@@ -160,6 +160,7 @@ out:
 
 int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
 {
+       struct inode *inode = &ip->i_inode;
        struct posix_acl *acl;
        char *data;
        unsigned int len;
@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
        if (IS_ERR(acl))
                return PTR_ERR(acl);
        if (!acl)
-               return gfs2_setattr_simple(ip, attr);
+               return gfs2_setattr_simple(inode, attr);
 
        error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
        if (error)
index f9fbbe9..4858e1f 100644 (file)
@@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        if (&ip->i_inode == sdp->sd_rindex)
                rblocks += 2 * RES_STATFS;
        if (alloc_required)
-               rblocks += gfs2_rg_blocks(al);
+               rblocks += gfs2_rg_blocks(ip);
 
        error = gfs2_trans_begin(sdp, rblocks,
                                 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        u64 to = pos + copied;
        void *kaddr;
        unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
-       struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
 
        BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
        kaddr = kmap_atomic(page, KM_USER0);
@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        if (copied) {
                if (inode->i_size < to)
                        i_size_write(inode, to);
-               gfs2_dinode_out(ip, di);
                mark_inode_dirty(inode);
        }
 
@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
                gfs2_page_add_databufs(ip, page, from, to);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
-       if (ret > 0) {
-               gfs2_dinode_out(ip, dibh->b_data);
-               mark_inode_dirty(inode);
-       }
 
        if (inode == sdp->sd_rindex) {
                adjust_fs_space(inode);
index 7878c47..41d494d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
+#include <linux/blkdev.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
 
@@ -36,11 +37,6 @@ struct metapath {
        __u16 mp_list[GFS2_MAX_META_HEIGHT];
 };
 
-typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
-                            struct buffer_head *bh, __be64 *top,
-                            __be64 *bottom, unsigned int height,
-                            void *data);
-
 struct strip_mine {
        int sm_first;
        unsigned int sm_height;
@@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
        return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
 }
 
+static void gfs2_metapath_ra(struct gfs2_glock *gl,
+                            const struct buffer_head *bh, const __be64 *pos)
+{
+       struct buffer_head *rabh;
+       const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
+       const __be64 *t;
+
+       for (t = pos; t < endp; t++) {
+               if (!*t)
+                       continue;
+
+               rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
+               if (trylock_buffer(rabh)) {
+                       if (!buffer_uptodate(rabh)) {
+                               rabh->b_end_io = end_buffer_read_sync;
+                               submit_bh(READA | REQ_META, rabh);
+                               continue;
+                       }
+                       unlock_buffer(rabh);
+               }
+               brelse(rabh);
+       }
+}
+
 /**
  * lookup_metapath - Walk the metadata tree to a specific point
  * @ip: The inode
@@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct super_block *sb = sdp->sd_vfs;
        struct buffer_head *dibh = mp->mp_bh[0];
        u64 bn, dblock = 0;
        unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
        unsigned dblks = 0;
        unsigned ptrs_per_blk;
        const unsigned end_of_metadata = height - 1;
+       int ret;
        int eob = 0;
        enum alloc_state state;
        __be64 *ptr;
@@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
                        dblock = bn;
                        while (n-- > 0)
                                *ptr++ = cpu_to_be64(bn++);
+                       if (buffer_zeronew(bh_map)) {
+                               ret = sb_issue_zeroout(sb, dblock, dblks,
+                                                      GFP_NOFS);
+                               if (ret) {
+                                       fs_err(sdp,
+                                              "Failed to zero data buffers\n");
+                                       clear_buffer_zeronew(bh_map);
+                               }
+                       }
                        break;
                }
        } while ((state != ALLOC_DATA) || !dblock);
@@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
        return ret;
 }
 
-/**
- * recursive_scan - recursively scan through the end of a file
- * @ip: the inode
- * @dibh: the dinode buffer
- * @mp: the path through the metadata to the point to start
- * @height: the height the recursion is at
- * @block: the indirect block to look at
- * @first: 1 if this is the first block
- * @bc: the call to make for each piece of metadata
- * @data: data opaque to this function to pass to @bc
- *
- * When this is first called @height and @block should be zero and
- * @first should be 1.
- *
- * Returns: errno
- */
-
-static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
-                         struct metapath *mp, unsigned int height,
-                         u64 block, int first, block_call_t bc,
-                         void *data)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct buffer_head *bh = NULL;
-       __be64 *top, *bottom;
-       u64 bn;
-       int error;
-       int mh_size = sizeof(struct gfs2_meta_header);
-
-       if (!height) {
-               error = gfs2_meta_inode_buffer(ip, &bh);
-               if (error)
-                       return error;
-               dibh = bh;
-
-               top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
-               bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
-       } else {
-               error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
-               if (error)
-                       return error;
-
-               top = (__be64 *)(bh->b_data + mh_size) +
-                                 (first ? mp->mp_list[height] : 0);
-
-               bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
-       }
-
-       error = bc(ip, dibh, bh, top, bottom, height, data);
-       if (error)
-               goto out;
-
-       if (height < ip->i_height - 1)
-               for (; top < bottom; top++, first = 0) {
-                       if (!*top)
-                               continue;
-
-                       bn = be64_to_cpu(*top);
-
-                       error = recursive_scan(ip, dibh, mp, height + 1, bn,
-                                              first, bc, data);
-                       if (error)
-                               break;
-               }
-
-out:
-       brelse(bh);
-       return error;
-}
-
 /**
  * do_strip - Look for a layer a particular layer of the file and strip it off
  * @ip: the inode
@@ -752,9 +713,8 @@ out:
 
 static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                    struct buffer_head *bh, __be64 *top, __be64 *bottom,
-                   unsigned int height, void *data)
+                   unsigned int height, struct strip_mine *sm)
 {
-       struct strip_mine *sm = data;
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrp_list rlist;
        u64 bn, bstart;
@@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        else if (ip->i_depth)
                revokes = sdp->sd_inptrs;
 
-       if (ip != GFS2_I(sdp->sd_rindex))
-               error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
-       else if (!sdp->sd_rgrps)
-               error = gfs2_ri_update(ip);
-
        if (error)
                return error;
 
@@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                        blen++;
                else {
                        if (bstart)
-                               gfs2_rlist_add(sdp, &rlist, bstart);
+                               gfs2_rlist_add(ip, &rlist, bstart);
 
                        bstart = bn;
                        blen = 1;
@@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        }
 
        if (bstart)
-               gfs2_rlist_add(sdp, &rlist, bstart);
+               gfs2_rlist_add(ip, &rlist, bstart);
        else
                goto out; /* Nothing to do */
 
@@ -887,11 +842,81 @@ out_rg_gunlock:
 out_rlist:
        gfs2_rlist_free(&rlist);
 out:
-       if (ip != GFS2_I(sdp->sd_rindex))
-               gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
        return error;
 }
 
+/**
+ * recursive_scan - recursively scan through the end of a file
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @mp: the path through the metadata to the point to start
+ * @height: the height the recursion is at
+ * @block: the indirect block to look at
+ * @first: 1 if this is the first block
+ * @sm: data opaque to this function to pass to @bc
+ *
+ * When this is first called @height and @block should be zero and
+ * @first should be 1.
+ *
+ * Returns: errno
+ */
+
+static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
+                         struct metapath *mp, unsigned int height,
+                         u64 block, int first, struct strip_mine *sm)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct buffer_head *bh = NULL;
+       __be64 *top, *bottom;
+       u64 bn;
+       int error;
+       int mh_size = sizeof(struct gfs2_meta_header);
+
+       if (!height) {
+               error = gfs2_meta_inode_buffer(ip, &bh);
+               if (error)
+                       return error;
+               dibh = bh;
+
+               top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
+               bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
+       } else {
+               error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
+               if (error)
+                       return error;
+
+               top = (__be64 *)(bh->b_data + mh_size) +
+                                 (first ? mp->mp_list[height] : 0);
+
+               bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
+       }
+
+       error = do_strip(ip, dibh, bh, top, bottom, height, sm);
+       if (error)
+               goto out;
+
+       if (height < ip->i_height - 1) {
+
+               gfs2_metapath_ra(ip->i_gl, bh, top);
+
+               for (; top < bottom; top++, first = 0) {
+                       if (!*top)
+                               continue;
+
+                       bn = be64_to_cpu(*top);
+
+                       error = recursive_scan(ip, dibh, mp, height + 1, bn,
+                                              first, sm);
+                       if (error)
+                               break;
+               }
+       }
+out:
+       brelse(bh);
+       return error;
+}
+
+
 /**
  * gfs2_block_truncate_page - Deal with zeroing out data for truncate
  *
@@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
                sm.sm_first = !!size;
                sm.sm_height = height;
 
-               error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
+               error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm);
                if (error)
                        break;
        }
index 1cc2f8e..8ccad24 100644 (file)
@@ -240,16 +240,15 @@ fail:
        return error;
 }
 
-static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
-                                u64 offset, unsigned int size)
+static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
+                                unsigned int size)
 {
        struct buffer_head *dibh;
        int error;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (!error) {
-               offset += sizeof(struct gfs2_dinode);
-               memcpy(buf, dibh->b_data + offset, size);
+               memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
                brelse(dibh);
        }
 
@@ -261,13 +260,12 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
  * gfs2_dir_read_data - Read a data from a directory inode
  * @ip: The GFS2 Inode
  * @buf: The buffer to place result into
- * @offset: File offset to begin jdata_readng from
  * @size: Amount of data to transfer
  *
  * Returns: The amount of data actually copied or the error
  */
-static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
-                             unsigned int size, unsigned ra)
+static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
+                             unsigned int size)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        u64 lblock, dblock;
@@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
        unsigned int o;
        int copied = 0;
        int error = 0;
-       u64 disksize = i_size_read(&ip->i_inode);
-
-       if (offset >= disksize)
-               return 0;
-
-       if (offset + size > disksize)
-               size = disksize - offset;
-
-       if (!size)
-               return 0;
 
        if (gfs2_is_stuffed(ip))
-               return gfs2_dir_read_stuffed(ip, buf, offset, size);
+               return gfs2_dir_read_stuffed(ip, buf, size);
 
        if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
                return -EINVAL;
 
-       lblock = offset;
+       lblock = 0;
        o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
 
        while (copied < size) {
@@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
                        if (error || !dblock)
                                goto fail;
                        BUG_ON(extlen < 1);
-                       if (!ra)
-                               extlen = 1;
                        bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
                } else {
                        error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
@@ -328,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
                extlen--;
                memcpy(buf, bh->b_data + o, amount);
                brelse(bh);
-               buf += amount;
+               buf += (amount/sizeof(__be64));
                copied += amount;
                lblock++;
                o = sizeof(struct gfs2_meta_header);
@@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
        if (hc == NULL)
                return ERR_PTR(-ENOMEM);
 
-       ret = gfs2_dir_read_data(ip, (char *)hc, 0, hsize, 1);
+       ret = gfs2_dir_read_data(ip, hc, hsize);
        if (ret < 0) {
                kfree(hc);
                return ERR_PTR(ret);
@@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
        const struct qstr *name = &dentry->d_name;
        struct gfs2_dirent *dent, *prev = NULL;
        struct buffer_head *bh;
-       int error;
 
        /* Returns _either_ the entry (if its first in block) or the
           previous entry otherwise */
@@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
        }
        brelse(bh);
 
-       error = gfs2_meta_inode_buffer(dip, &bh);
-       if (error)
-               return error;
-
        if (!dip->i_entries)
                gfs2_consist_inode(dip);
-       gfs2_trans_add_bh(dip->i_gl, bh, 1);
        dip->i_entries--;
        dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
        if (S_ISDIR(dentry->d_inode->i_mode))
                drop_nlink(&dip->i_inode);
-       gfs2_dinode_out(dip, bh->b_data);
-       brelse(bh);
        mark_inode_dirty(&dip->i_inode);
 
-       return error;
+       return 0;
 }
 
 /**
@@ -1829,10 +1807,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
        if (error)
                goto out_put;
 
-       error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
-       if (error)
-               goto out_qs;
-
        /*  Count the number of leaves  */
        bh = leaf_bh;
 
@@ -1847,7 +1821,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
                if (blk != leaf_no)
                        brelse(bh);
 
-               gfs2_rlist_add(sdp, &rlist, blk);
+               gfs2_rlist_add(dip, &rlist, blk);
                l_blocks++;
        }
 
@@ -1911,8 +1885,6 @@ out_rg_gunlock:
        gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
 out_rlist:
        gfs2_rlist_free(&rlist);
-       gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
-out_qs:
        gfs2_quota_unhold(dip);
 out_put:
        gfs2_alloc_put(dip);
index edeb9e8..5002408 100644 (file)
@@ -59,15 +59,24 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
        struct gfs2_holder i_gh;
        loff_t error;
 
-       if (origin == 2) {
+       switch (origin) {
+       case SEEK_END: /* These reference inode->i_size */
+       case SEEK_DATA:
+       case SEEK_HOLE:
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
                                           &i_gh);
                if (!error) {
                        error = generic_file_llseek_unlocked(file, offset, origin);
                        gfs2_glock_dq_uninit(&i_gh);
                }
-       } else
+               break;
+       case SEEK_CUR:
+       case SEEK_SET:
                error = generic_file_llseek_unlocked(file, offset, origin);
+               break;
+       default:
+               error = -EINVAL;
+       }
 
        return error;
 }
@@ -357,8 +366,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        unsigned int data_blocks, ind_blocks, rblocks;
        struct gfs2_holder gh;
        struct gfs2_alloc *al;
+       loff_t size;
        int ret;
 
+       /* Wait if fs is frozen. This is racy so we check again later on
+        * and retry if the fs has been frozen after the page lock has
+        * been acquired
+        */
+       vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
        if (ret)
@@ -367,8 +383,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
 
-       if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE))
+       if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) {
+               lock_page(page);
+               if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
+                       ret = -EAGAIN;
+                       unlock_page(page);
+               }
                goto out_unlock;
+       }
+
        ret = -ENOMEM;
        al = gfs2_alloc_get(ip);
        if (al == NULL)
@@ -388,7 +411,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                rblocks += data_blocks ? data_blocks : 1;
        if (ind_blocks || data_blocks) {
                rblocks += RES_STATFS + RES_QUOTA;
-               rblocks += gfs2_rg_blocks(al);
+               rblocks += gfs2_rg_blocks(ip);
        }
        ret = gfs2_trans_begin(sdp, rblocks, 0);
        if (ret)
@@ -396,21 +419,29 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        lock_page(page);
        ret = -EINVAL;
-       last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
-       if (page->index > last_index)
-               goto out_unlock_page;
+       size = i_size_read(inode);
+       last_index = (size - 1) >> PAGE_CACHE_SHIFT;
+       /* Check page index against inode size */
+       if (size == 0 || (page->index > last_index))
+               goto out_trans_end;
+
+       ret = -EAGAIN;
+       /* If truncated, we must retry the operation, we may have raced
+        * with the glock demotion code.
+        */
+       if (!PageUptodate(page) || page->mapping != inode->i_mapping)
+               goto out_trans_end;
+
+       /* Unstuff, if required, and allocate backing blocks for page */
        ret = 0;
-       if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
-               goto out_unlock_page;
-       if (gfs2_is_stuffed(ip)) {
+       if (gfs2_is_stuffed(ip))
                ret = gfs2_unstuff_dinode(ip, page);
-               if (ret)
-                       goto out_unlock_page;
-       }
-       ret = gfs2_allocate_page_backing(page);
+       if (ret == 0)
+               ret = gfs2_allocate_page_backing(page);
 
-out_unlock_page:
-       unlock_page(page);
+out_trans_end:
+       if (ret)
+               unlock_page(page);
        gfs2_trans_end(sdp);
 out_trans_fail:
        gfs2_inplace_release(ip);
@@ -422,11 +453,17 @@ out_unlock:
        gfs2_glock_dq(&gh);
 out:
        gfs2_holder_uninit(&gh);
-       if (ret == -ENOMEM)
-               ret = VM_FAULT_OOM;
-       else if (ret)
-               ret = VM_FAULT_SIGBUS;
-       return ret;
+       if (ret == 0) {
+               set_page_dirty(page);
+               /* This check must be post dropping of transaction lock */
+               if (inode->i_sb->s_frozen == SB_UNFROZEN) {
+                       wait_on_page_writeback(page);
+               } else {
+                       ret = -EAGAIN;
+                       unlock_page(page);
+               }
+       }
+       return block_page_mkwrite_return(ret);
 }
 
 static const struct vm_operations_struct gfs2_vm_ops = {
@@ -551,8 +588,16 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * @end: the end position in the file to sync
  * @datasync: set if we can ignore timestamp changes
  *
- * The VFS will flush data for us. We only need to worry
- * about metadata here.
+ * We split the data flushing here so that we don't wait for the data
+ * until after we've also sent the metadata to disk. Note that for
+ * data=ordered, we will write & wait for the data at the log flush
+ * stage anyway, so this is unlikely to make much of a difference
+ * except in the data=writeback case.
+ *
+ * If the fdatawrite fails due to any reason except -EIO, we will
+ * continue the remainder of the fsync, although we'll still report
+ * the error at the end. This is to match filemap_write_and_wait_range()
+ * behaviour.
  *
  * Returns: errno
  */
@@ -560,30 +605,34 @@ static int gfs2_close(struct inode *inode, struct file *file)
 static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
                      int datasync)
 {
-       struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        struct gfs2_inode *ip = GFS2_I(inode);
-       int ret;
+       int ret, ret1 = 0;
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret)
-               return ret;
-       mutex_lock(&inode->i_mutex);
+       if (mapping->nrpages) {
+               ret1 = filemap_fdatawrite_range(mapping, start, end);
+               if (ret1 == -EIO)
+                       return ret1;
+       }
 
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
 
        if (sync_state) {
                ret = sync_inode_metadata(inode, 1);
-               if (ret) {
-                       mutex_unlock(&inode->i_mutex);
+               if (ret)
                        return ret;
-               }
-               gfs2_ail_flush(ip->i_gl);
+               if (gfs2_is_jdata(ip))
+                       filemap_write_and_wait(mapping);
+               gfs2_ail_flush(ip->i_gl, 1);
        }
 
-       mutex_unlock(&inode->i_mutex);
-       return 0;
+       if (mapping->nrpages)
+               ret = filemap_fdatawait_range(mapping, start, end);
+
+       return ret ? ret : ret1;
 }
 
 /**
@@ -620,135 +669,18 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        return generic_file_aio_write(iocb, iov, nr_segs, pos);
 }
 
-static int empty_write_end(struct page *page, unsigned from,
-                          unsigned to, int mode)
-{
-       struct inode *inode = page->mapping->host;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct buffer_head *bh;
-       unsigned offset, blksize = 1 << inode->i_blkbits;
-       pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
-
-       zero_user(page, from, to-from);
-       mark_page_accessed(page);
-
-       if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) {
-               if (!gfs2_is_writeback(ip))
-                       gfs2_page_add_databufs(ip, page, from, to);
-
-               block_commit_write(page, from, to);
-               return 0;
-       }
-
-       offset = 0;
-       bh = page_buffers(page);
-       while (offset < to) {
-               if (offset >= from) {
-                       set_buffer_uptodate(bh);
-                       mark_buffer_dirty(bh);
-                       clear_buffer_new(bh);
-                       write_dirty_buffer(bh, WRITE);
-               }
-               offset += blksize;
-               bh = bh->b_this_page;
-       }
-
-       offset = 0;
-       bh = page_buffers(page);
-       while (offset < to) {
-               if (offset >= from) {
-                       wait_on_buffer(bh);
-                       if (!buffer_uptodate(bh))
-                               return -EIO;
-               }
-               offset += blksize;
-               bh = bh->b_this_page;
-       }
-       return 0;
-}
-
-static int needs_empty_write(sector_t block, struct inode *inode)
-{
-       int error;
-       struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
-
-       bh_map.b_size = 1 << inode->i_blkbits;
-       error = gfs2_block_map(inode, block, &bh_map, 0);
-       if (unlikely(error))
-               return error;
-       return !buffer_mapped(&bh_map);
-}
-
-static int write_empty_blocks(struct page *page, unsigned from, unsigned to,
-                             int mode)
-{
-       struct inode *inode = page->mapping->host;
-       unsigned start, end, next, blksize;
-       sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-       int ret;
-
-       blksize = 1 << inode->i_blkbits;
-       next = end = 0;
-       while (next < from) {
-               next += blksize;
-               block++;
-       }
-       start = next;
-       do {
-               next += blksize;
-               ret = needs_empty_write(block, inode);
-               if (unlikely(ret < 0))
-                       return ret;
-               if (ret == 0) {
-                       if (end) {
-                               ret = __block_write_begin(page, start, end - start,
-                                                         gfs2_block_map);
-                               if (unlikely(ret))
-                                       return ret;
-                               ret = empty_write_end(page, start, end, mode);
-                               if (unlikely(ret))
-                                       return ret;
-                               end = 0;
-                       }
-                       start = next;
-               }
-               else
-                       end = next;
-               block++;
-       } while (next < to);
-
-       if (end) {
-               ret = __block_write_begin(page, start, end - start, gfs2_block_map);
-               if (unlikely(ret))
-                       return ret;
-               ret = empty_write_end(page, start, end, mode);
-               if (unlikely(ret))
-                       return ret;
-       }
-
-       return 0;
-}
-
 static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                           int mode)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct buffer_head *dibh;
        int error;
-       u64 start = offset >> PAGE_CACHE_SHIFT;
-       unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
-       u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
-       pgoff_t curr;
-       struct page *page;
-       unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
-       unsigned int from, to;
-
-       if (!end_offset)
-               end_offset = PAGE_CACHE_SIZE;
+       unsigned int nr_blks;
+       sector_t lblock = offset >> inode->i_blkbits;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (unlikely(error))
-               goto out;
+               return error;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 
@@ -758,40 +690,31 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                        goto out;
        }
 
-       curr = start;
-       offset = start << PAGE_CACHE_SHIFT;
-       from = start_offset;
-       to = PAGE_CACHE_SIZE;
-       while (curr <= end) {
-               page = grab_cache_page_write_begin(inode->i_mapping, curr,
-                                                  AOP_FLAG_NOFS);
-               if (unlikely(!page)) {
-                       error = -ENOMEM;
-                       goto out;
-               }
+       while (len) {
+               struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
+               bh_map.b_size = len;
+               set_buffer_zeronew(&bh_map);
 
-               if (curr == end)
-                       to = end_offset;
-               error = write_empty_blocks(page, from, to, mode);
-               if (!error && offset + to > inode->i_size &&
-                   !(mode & FALLOC_FL_KEEP_SIZE)) {
-                       i_size_write(inode, offset + to);
-               }
-               unlock_page(page);
-               page_cache_release(page);
-               if (error)
+               error = gfs2_block_map(inode, lblock, &bh_map, 1);
+               if (unlikely(error))
                        goto out;
-               curr++;
-               offset += PAGE_CACHE_SIZE;
-               from = 0;
+               len -= bh_map.b_size;
+               nr_blks = bh_map.b_size >> inode->i_blkbits;
+               lblock += nr_blks;
+               if (!buffer_new(&bh_map))
+                       continue;
+               if (unlikely(!buffer_zeronew(&bh_map))) {
+                       error = -EIO;
+                       goto out;
+               }
        }
+       if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
+               i_size_write(inode, offset + len);
 
-       gfs2_dinode_out(ip, dibh->b_data);
        mark_inode_dirty(inode);
 
-       brelse(dibh);
-
 out:
+       brelse(dibh);
        return error;
 }
 
@@ -799,7 +722,7 @@ static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
                            unsigned int *data_blocks, unsigned int *ind_blocks)
 {
        const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone;
+       unsigned int max_blocks = ip->i_rgd->rd_free_clone;
        unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
 
        for (tmp = max_data; tmp > sdp->sd_diptrs;) {
@@ -831,6 +754,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
        int error;
        loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);
        loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
+       loff_t max_chunk_size = UINT_MAX & bsize_mask;
        next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
 
        /* We only support the FALLOC_FL_KEEP_SIZE mode */
@@ -884,11 +808,12 @@ retry:
                        goto out_qunlock;
                }
                max_bytes = bytes;
-               calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks);
+               calc_max_reserv(ip, (len > max_chunk_size)? max_chunk_size: len,
+                               &max_bytes, &data_blocks, &ind_blocks);
                al->al_requested = data_blocks + ind_blocks;
 
                rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
-                         RES_RG_HDR + gfs2_rg_blocks(al);
+                         RES_RG_HDR + gfs2_rg_blocks(ip);
                if (gfs2_is_jdata(ip))
                        rblocks += data_blocks ? data_blocks : 1;
 
index da21eca..78418b4 100644 (file)
 #include "trans.h"
 #include "dir.h"
 
+static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
+{
+       fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
+              bh, (unsigned long long)bh->b_blocknr, bh->b_state,
+              bh->b_page->mapping, bh->b_page->flags);
+       fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
+              gl->gl_name.ln_type, gl->gl_name.ln_number,
+              gfs2_glock2aspace(gl));
+       gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
+}
+
 /**
  * __gfs2_ail_flush - remove all buffers for a given lock from the AIL
  * @gl: the glock
+ * @fsync: set when called from fsync (not all buffers will be clean)
  *
  * None of the buffers should be dirty, locked, or pinned.
  */
 
-static void __gfs2_ail_flush(struct gfs2_glock *gl)
+static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct list_head *head = &gl->gl_ail_list;
-       struct gfs2_bufdata *bd;
+       struct gfs2_bufdata *bd, *tmp;
        struct buffer_head *bh;
+       const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock);
+       sector_t blocknr;
 
+       gfs2_log_lock(sdp);
        spin_lock(&sdp->sd_ail_lock);
-       while (!list_empty(head)) {
-               bd = list_entry(head->next, struct gfs2_bufdata,
-                               bd_ail_gl_list);
+       list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
                bh = bd->bd_bh;
-               gfs2_remove_from_ail(bd);
-               bd->bd_bh = NULL;
+               if (bh->b_state & b_state) {
+                       if (fsync)
+                               continue;
+                       gfs2_ail_error(gl, bh);
+               }
+               blocknr = bh->b_blocknr;
                bh->b_private = NULL;
-               spin_unlock(&sdp->sd_ail_lock);
+               gfs2_remove_from_ail(bd); /* drops ref on bh */
 
-               bd->bd_blkno = bh->b_blocknr;
-               gfs2_log_lock(sdp);
-               gfs2_assert_withdraw(sdp, !buffer_busy(bh));
-               gfs2_trans_add_revoke(sdp, bd);
-               gfs2_log_unlock(sdp);
+               bd->bd_bh = NULL;
+               bd->bd_blkno = blocknr;
 
-               spin_lock(&sdp->sd_ail_lock);
+               gfs2_trans_add_revoke(sdp, bd);
        }
-       gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+       BUG_ON(!fsync && atomic_read(&gl->gl_ail_count));
        spin_unlock(&sdp->sd_ail_lock);
+       gfs2_log_unlock(sdp);
 }
 
 
@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
        BUG_ON(current->journal_info);
        current->journal_info = &tr;
 
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, 0);
 
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
 }
 
-void gfs2_ail_flush(struct gfs2_glock *gl)
+void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        unsigned int revokes = atomic_read(&gl->gl_ail_count);
@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
        ret = gfs2_trans_begin(sdp, 0, revokes);
        if (ret)
                return;
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, fsync);
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
 }
@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
 static void rgrp_go_sync(struct gfs2_glock *gl)
 {
        struct address_space *metamapping = gfs2_glock2aspace(gl);
+       struct gfs2_rgrpd *rgd;
        int error;
 
        if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
        error = filemap_fdatawait(metamapping);
         mapping_set_error(metamapping, error);
        gfs2_ail_empty_gl(gl);
+
+       spin_lock(&gl->gl_spin);
+       rgd = gl->gl_object;
+       if (rgd)
+               gfs2_free_clones(rgd);
+       spin_unlock(&gl->gl_spin);
 }
 
 /**
@@ -429,33 +451,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
        return 0;
 }
 
-/**
- * rgrp_go_lock - operation done after an rgrp lock is locked by
- *    a first holder on this node.
- * @gl: the glock
- * @flags:
- *
- * Returns: errno
- */
-
-static int rgrp_go_lock(struct gfs2_holder *gh)
-{
-       return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
-}
-
-/**
- * rgrp_go_unlock - operation done before an rgrp lock is unlocked by
- *    a last holder on this node.
- * @gl: the glock
- * @flags:
- *
- */
-
-static void rgrp_go_unlock(struct gfs2_holder *gh)
-{
-       gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
-}
-
 /**
  * trans_go_sync - promote/demote the transaction glock
  * @gl: the glock
@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
        .go_xmote_th = rgrp_go_sync,
        .go_inval = rgrp_go_inval,
-       .go_lock = rgrp_go_lock,
-       .go_unlock = rgrp_go_unlock,
+       .go_lock = gfs2_rgrp_go_lock,
+       .go_unlock = gfs2_rgrp_go_unlock,
        .go_dump = gfs2_rgrp_dump,
        .go_type = LM_TYPE_RGRP,
        .go_flags = GLOF_ASPACE,
index 6fce409..bf95a2d 100644 (file)
@@ -23,6 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops;
 extern const struct gfs2_glock_operations gfs2_journal_glops;
 extern const struct gfs2_glock_operations *gfs2_glops_list[];
 
-extern void gfs2_ail_flush(struct gfs2_glock *gl);
+extern void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync);
 
 #endif /* __GLOPS_DOT_H__ */
index 892ac37..7389dfd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/rcupdate.h>
 #include <linux/rculist_bl.h>
 #include <linux/completion.h>
+#include <linux/rbtree.h>
 
 #define DIO_WAIT       0x00000010
 #define DIO_METADATA   0x00000020
@@ -78,8 +79,7 @@ struct gfs2_bitmap {
 };
 
 struct gfs2_rgrpd {
-       struct list_head rd_list;       /* Link with superblock */
-       struct list_head rd_list_mru;
+       struct rb_node rd_node;         /* Link with superblock */
        struct gfs2_glock *rd_gl;       /* Glock for this rgrp */
        u64 rd_addr;                    /* grp block disk address */
        u64 rd_data0;                   /* first data location */
@@ -91,10 +91,7 @@ struct gfs2_rgrpd {
        u32 rd_dinodes;
        u64 rd_igeneration;
        struct gfs2_bitmap *rd_bits;
-       struct mutex rd_mutex;
-       struct gfs2_log_element rd_le;
        struct gfs2_sbd *rd_sbd;
-       unsigned int rd_bh_count;
        u32 rd_last_alloc;
        u32 rd_flags;
 #define GFS2_RDF_CHECK         0x10000000 /* check for unlinked inodes */
@@ -106,12 +103,15 @@ struct gfs2_rgrpd {
 enum gfs2_state_bits {
        BH_Pinned = BH_PrivateStart,
        BH_Escaped = BH_PrivateStart + 1,
+       BH_Zeronew = BH_PrivateStart + 2,
 };
 
 BUFFER_FNS(Pinned, pinned)
 TAS_BUFFER_FNS(Pinned, pinned)
 BUFFER_FNS(Escaped, escaped)
 TAS_BUFFER_FNS(Escaped, escaped)
+BUFFER_FNS(Zeronew, zeronew)
+TAS_BUFFER_FNS(Zeronew, zeronew)
 
 struct gfs2_bufdata {
        struct buffer_head *bd_bh;
@@ -246,7 +246,6 @@ struct gfs2_glock {
 
 struct gfs2_alloc {
        /* Quota stuff */
-
        struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
        struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
        unsigned int al_qd_num;
@@ -255,18 +254,13 @@ struct gfs2_alloc {
        u32 al_alloced; /* Filled in by gfs2_alloc_*() */
 
        /* Filled in by gfs2_inplace_reserve() */
-
-       unsigned int al_line;
-       char *al_file;
-       struct gfs2_holder al_ri_gh;
        struct gfs2_holder al_rgd_gh;
-       struct gfs2_rgrpd *al_rgd;
-
 };
 
 enum {
        GIF_INVALID             = 0,
        GIF_QD_LOCKED           = 1,
+       GIF_ALLOC_FAILED        = 2,
        GIF_SW_PAGED            = 3,
 };
 
@@ -282,6 +276,7 @@ struct gfs2_inode {
        struct gfs2_holder i_iopen_gh;
        struct gfs2_holder i_gh; /* for prepare/commit_write only */
        struct gfs2_alloc *i_alloc;
+       struct gfs2_rgrpd *i_rgd;
        u64 i_goal;     /* goal block for allocations */
        struct rw_semaphore i_rw_mutex;
        struct list_head i_trunc_list;
@@ -574,9 +569,7 @@ struct gfs2_sbd {
        int sd_rindex_uptodate;
        spinlock_t sd_rindex_spin;
        struct mutex sd_rindex_mutex;
-       struct list_head sd_rindex_list;
-       struct list_head sd_rindex_mru_list;
-       struct gfs2_rgrpd *sd_rindex_forward;
+       struct rb_root sd_rindex_tree;
        unsigned int sd_rgrps;
        unsigned int sd_max_rg_data;
 
index 6525b80..cfd4959 100644 (file)
@@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
                        goto fail_quota_locks;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        al->al_rgd->rd_length +
+                                        dip->i_rgd->rd_length +
                                         2 * RES_DINODE +
                                         RES_STATFS + RES_QUOTA, 0);
                if (error)
@@ -613,8 +613,7 @@ fail_end_trans:
        gfs2_trans_end(sdp);
 
 fail_ipreserv:
-       if (dip->i_alloc->al_rgd)
-               gfs2_inplace_release(dip);
+       gfs2_inplace_release(dip);
 
 fail_quota_locks:
        gfs2_quota_unlock(dip);
@@ -661,7 +660,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
 
 static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                             unsigned int mode, dev_t dev, const char *symname,
-                            unsigned int size)
+                            unsigned int size, int excl)
 {
        const struct qstr *name = &dentry->d_name;
        struct gfs2_holder ghs[2];
@@ -681,6 +680,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                goto fail;
 
        error = create_ok(dip, name, mode);
+       if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
+               inode = gfs2_lookupi(dir, &dentry->d_name, 0);
+               gfs2_glock_dq_uninit(ghs);
+               d_instantiate(dentry, inode);
+               return IS_ERR(inode) ? PTR_ERR(inode) : 0;
+       }
        if (error)
                goto fail_gunlock;
 
@@ -723,21 +728,22 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                brelse(bh);
 
        gfs2_trans_end(sdp);
-       if (dip->i_alloc->al_rgd)
-               gfs2_inplace_release(dip);
+       gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        gfs2_alloc_put(dip);
-       gfs2_glock_dq_uninit_m(2, ghs);
        mark_inode_dirty(inode);
+       gfs2_glock_dq_uninit_m(2, ghs);
        d_instantiate(dentry, inode);
        return 0;
 
 fail_gunlock2:
        gfs2_glock_dq_uninit(ghs + 1);
-       if (inode && !IS_ERR(inode))
-               iput(inode);
 fail_gunlock:
        gfs2_glock_dq_uninit(ghs);
+       if (inode && !IS_ERR(inode)) {
+               set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
+               iput(inode);
+       }
 fail:
        if (bh)
                brelse(bh);
@@ -756,24 +762,10 @@ fail:
 static int gfs2_create(struct inode *dir, struct dentry *dentry,
                       int mode, struct nameidata *nd)
 {
-       struct inode *inode;
-       int ret;
-
-       for (;;) {
-               ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
-               if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
-                       return ret;
-
-               inode = gfs2_lookupi(dir, &dentry->d_name, 0);
-               if (inode) {
-                       if (!IS_ERR(inode))
-                               break;
-                       return PTR_ERR(inode);
-               }
-       }
-
-       d_instantiate(dentry, inode);
-       return 0;
+       int excl = 0;
+       if (nd && (nd->flags & LOOKUP_EXCL))
+               excl = 1;
+       return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
 }
 
 /**
@@ -900,7 +892,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        gfs2_rg_blocks(al) +
+                                        gfs2_rg_blocks(dip) +
                                         2 * RES_DINODE + RES_STATFS +
                                         RES_QUOTA, 0);
                if (error)
@@ -922,8 +914,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        inc_nlink(&ip->i_inode);
        ip->i_inode.i_ctime = CURRENT_TIME;
-       gfs2_dinode_out(ip, dibh->b_data);
-       mark_inode_dirty(&ip->i_inode);
+       ihold(inode);
+       d_instantiate(dentry, inode);
+       mark_inode_dirty(inode);
 
 out_brelse:
        brelse(dibh);
@@ -945,11 +938,6 @@ out_child:
 out_parent:
        gfs2_holder_uninit(ghs);
        gfs2_holder_uninit(ghs + 1);
-       if (!error) {
-               ihold(inode);
-               d_instantiate(dentry, inode);
-               mark_inode_dirty(inode);
-       }
        return error;
 }
 
@@ -1022,8 +1010,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
                clear_nlink(inode);
        else
                drop_nlink(inode);
-       gfs2_trans_add_bh(ip->i_gl, bh, 1);
-       gfs2_dinode_out(ip, bh->b_data);
        mark_inode_dirty(inode);
        if (inode->i_nlink == 0)
                gfs2_unlink_di(inode);
@@ -1051,13 +1037,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
        struct buffer_head *bh;
        struct gfs2_holder ghs[3];
        struct gfs2_rgrpd *rgd;
-       struct gfs2_holder ri_gh;
        int error;
 
-       error = gfs2_rindex_hold(sdp, &ri_gh);
-       if (error)
-               return error;
-
        gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
        gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);
 
@@ -1114,7 +1095,6 @@ out_child:
        gfs2_glock_dq(ghs);
 out_parent:
        gfs2_holder_uninit(ghs);
-       gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
 
@@ -1137,7 +1117,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
        if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
                return -ENAMETOOLONG;
 
-       return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size);
+       return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
 }
 
 /**
@@ -1151,7 +1131,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
 
 static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0);
+       return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0);
 }
 
 /**
@@ -1166,7 +1146,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
                      dev_t dev)
 {
-       return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0);
+       return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0);
 }
 
 /*
@@ -1232,7 +1212,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
        struct gfs2_inode *nip = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(odir);
-       struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh;
+       struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
        struct gfs2_rgrpd *nrgd;
        unsigned int num_gh;
        int dir_rename = 0;
@@ -1246,10 +1226,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                        return 0;
        }
 
-       error = gfs2_rindex_hold(sdp, &ri_gh);
-       if (error)
-               return error;
-
        if (odip != ndip) {
                error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
                                           0, &r_gh);
@@ -1386,12 +1362,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
 
                al->al_requested = sdp->sd_max_dirres;
 
-               error = gfs2_inplace_reserve_ri(ndip);
+               error = gfs2_inplace_reserve(ndip);
                if (error)
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        gfs2_rg_blocks(al) +
+                                        gfs2_rg_blocks(ndip) +
                                         4 * RES_DINODE + 4 * RES_LEAF +
                                         RES_STATFS + RES_QUOTA + 4, 0);
                if (error)
@@ -1457,7 +1433,6 @@ out_gunlock_r:
        if (r_gh.gh_gl)
                gfs2_glock_dq_uninit(&r_gh);
 out:
-       gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
 
@@ -1561,21 +1536,10 @@ int gfs2_permission(struct inode *inode, int mask)
        return error;
 }
 
-static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+static int __gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
 {
-       struct inode *inode = &ip->i_inode;
-       struct buffer_head *dibh;
-       int error;
-
-       error = gfs2_meta_inode_buffer(ip, &dibh);
-       if (error)
-               return error;
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
-       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-       gfs2_dinode_out(ip, dibh->b_data);
-       brelse(dibh);
        return 0;
 }
 
@@ -1587,19 +1551,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
  * Returns: errno
  */
 
-int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+int gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
 {
        int error;
 
        if (current->journal_info)
-               return __gfs2_setattr_simple(ip, attr);
+               return __gfs2_setattr_simple(inode, attr);
 
-       error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
+       error = gfs2_trans_begin(GFS2_SB(inode), RES_DINODE, 0);
        if (error)
                return error;
 
-       error = __gfs2_setattr_simple(ip, attr);
-       gfs2_trans_end(GFS2_SB(&ip->i_inode));
+       error = __gfs2_setattr_simple(inode, attr);
+       gfs2_trans_end(GFS2_SB(inode));
        return error;
 }
 
@@ -1637,7 +1601,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
        if (error)
                goto out_gunlock_q;
 
-       error = gfs2_setattr_simple(ip, attr);
+       error = gfs2_setattr_simple(inode, attr);
        if (error)
                goto out_end_trans;
 
@@ -1693,12 +1657,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
        else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
                error = gfs2_acl_chmod(ip, attr);
        else
-               error = gfs2_setattr_simple(ip, attr);
+               error = gfs2_setattr_simple(inode, attr);
 
 out:
-       gfs2_glock_dq_uninit(&i_gh);
        if (!error)
                mark_inode_dirty(inode);
+       gfs2_glock_dq_uninit(&i_gh);
        return error;
 }
 
index 8d90e0c..276e7b5 100644 (file)
@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
 extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
                                  int is_root);
 extern int gfs2_permission(struct inode *inode, int mask);
-extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
+extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
 extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
 extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
 
index 05bbb12..0301be6 100644 (file)
@@ -60,6 +60,29 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
        trace_gfs2_pin(bd, 1);
 }
 
+static bool buffer_is_rgrp(const struct gfs2_bufdata *bd)
+{
+       return bd->bd_gl->gl_name.ln_type == LM_TYPE_RGRP;
+}
+
+static void maybe_release_space(struct gfs2_bufdata *bd)
+{
+       struct gfs2_glock *gl = bd->bd_gl;
+       struct gfs2_sbd *sdp = gl->gl_sbd;
+       struct gfs2_rgrpd *rgd = gl->gl_object;
+       unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
+       struct gfs2_bitmap *bi = rgd->rd_bits + index;
+
+       if (bi->bi_clone == 0)
+               return;
+       if (sdp->sd_args.ar_discard)
+               gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
+       memcpy(bi->bi_clone + bi->bi_offset,
+              bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
+       clear_bit(GBF_FULL, &bi->bi_flags);
+       rgd->rd_free_clone = rgd->rd_free;
+}
+
 /**
  * gfs2_unpin - Unpin a buffer
  * @sdp: the filesystem the buffer belongs to
@@ -81,6 +104,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
        mark_buffer_dirty(bh);
        clear_buffer_pinned(bh);
 
+       if (buffer_is_rgrp(bd))
+               maybe_release_space(bd);
+
        spin_lock(&sdp->sd_ail_lock);
        if (bd->bd_ail) {
                list_del(&bd->bd_ail_st_list);
@@ -469,42 +495,6 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
        gfs2_revoke_clean(sdp);
 }
 
-static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
-{
-       struct gfs2_rgrpd *rgd;
-       struct gfs2_trans *tr = current->journal_info;
-
-       tr->tr_touched = 1;
-
-       rgd = container_of(le, struct gfs2_rgrpd, rd_le);
-
-       gfs2_log_lock(sdp);
-       if (!list_empty(&le->le_list)){
-               gfs2_log_unlock(sdp);
-               return;
-       }
-       gfs2_rgrp_bh_hold(rgd);
-       sdp->sd_log_num_rg++;
-       list_add(&le->le_list, &sdp->sd_log_le_rg);
-       gfs2_log_unlock(sdp);
-}
-
-static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
-{
-       struct list_head *head = &sdp->sd_log_le_rg;
-       struct gfs2_rgrpd *rgd;
-
-       while (!list_empty(head)) {
-               rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
-               list_del_init(&rgd->rd_le.le_list);
-               sdp->sd_log_num_rg--;
-
-               gfs2_rgrp_repolish_clones(rgd);
-               gfs2_rgrp_bh_put(rgd);
-       }
-       gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
-}
-
 /**
  * databuf_lo_add - Add a databuf to the transaction.
  *
@@ -705,8 +695,6 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
 
                brelse(bh_log);
                brelse(bh_ip);
-               if (error)
-                       break;
 
                sdp->sd_replayed_blocks++;
        }
@@ -771,8 +759,6 @@ const struct gfs2_log_operations gfs2_revoke_lops = {
 };
 
 const struct gfs2_log_operations gfs2_rg_lops = {
-       .lo_add = rg_lo_add,
-       .lo_after_commit = rg_lo_after_commit,
        .lo_name = "rg",
 };
 
index 079587e..7e823bb 100644 (file)
@@ -77,8 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        spin_lock_init(&sdp->sd_rindex_spin);
        mutex_init(&sdp->sd_rindex_mutex);
-       INIT_LIST_HEAD(&sdp->sd_rindex_list);
-       INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
+       sdp->sd_rindex_tree.rb_node = NULL;
 
        INIT_LIST_HEAD(&sdp->sd_jindex_list);
        spin_lock_init(&sdp->sd_jindex_spin);
@@ -652,7 +651,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                fs_err(sdp, "can't lookup journal index: %d\n", error);
                return PTR_ERR(sdp->sd_jindex);
        }
-       ip = GFS2_I(sdp->sd_jindex);
 
        /* Load in the journal index special file */
 
@@ -764,7 +762,6 @@ fail:
 static int init_inodes(struct gfs2_sbd *sdp, int undo)
 {
        int error = 0;
-       struct gfs2_inode *ip;
        struct inode *master = sdp->sd_master_dir->d_inode;
 
        if (undo)
@@ -789,7 +786,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
                fs_err(sdp, "can't get resource index inode: %d\n", error);
                goto fail_statfs;
        }
-       ip = GFS2_I(sdp->sd_rindex);
        sdp->sd_rindex_uptodate = 0;
 
        /* Read in the quota inode */
index 0e8bb13..7e528dc 100644 (file)
@@ -638,15 +638,18 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        unsigned long index = loc >> PAGE_CACHE_SHIFT;
        unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
        unsigned blocksize, iblock, pos;
-       struct buffer_head *bh, *dibh;
+       struct buffer_head *bh;
        struct page *page;
        void *kaddr, *ptr;
        struct gfs2_quota q, *qp;
        int err, nbytes;
        u64 size;
 
-       if (gfs2_is_stuffed(ip))
-               gfs2_unstuff_dinode(ip, NULL);
+       if (gfs2_is_stuffed(ip)) {
+               err = gfs2_unstuff_dinode(ip, NULL);
+               if (err)
+                       return err;
+       }
 
        memset(&q, 0, sizeof(struct gfs2_quota));
        err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q));
@@ -736,22 +739,13 @@ get_a_page:
                goto get_a_page;
        }
 
-       /* Update the disk inode timestamp and size (if extended) */
-       err = gfs2_meta_inode_buffer(ip, &dibh);
-       if (err)
-               goto out;
-
        size = loc + sizeof(struct gfs2_quota);
        if (size > inode->i_size)
                i_size_write(inode, size);
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
-       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-       gfs2_dinode_out(ip, dibh->b_data);
-       brelse(dibh);
        mark_inode_dirty(inode);
-
-out:
        return err;
+
 unlock_out:
        unlock_page(page);
        page_cache_release(page);
@@ -822,7 +816,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
                goto out_alloc;
 
        if (nalloc)
-               blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS;
+               blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
 
        error = gfs2_trans_begin(sdp, blocks, 0);
        if (error)
@@ -936,7 +930,9 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
        unsigned int x;
        int error = 0;
 
-       gfs2_quota_hold(ip, uid, gid);
+       error = gfs2_quota_hold(ip, uid, gid);
+       if (error)
+               return error;
 
        if (capable(CAP_SYS_RESOURCE) ||
            sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
@@ -1607,7 +1603,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
                error = gfs2_inplace_reserve(ip);
                if (error)
                        goto out_alloc;
-               blocks += gfs2_rg_blocks(al);
+               blocks += gfs2_rg_blocks(ip);
        }
 
        /* Some quotas span block boundaries and can update two blocks,
index 7f8af1e..96bd6d7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/prefetch.h>
 #include <linux/blkdev.h>
+#include <linux/rbtree.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -328,18 +329,22 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
 
 struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
 {
-       struct gfs2_rgrpd *rgd;
+       struct rb_node **newn;
+       struct gfs2_rgrpd *cur;
 
        spin_lock(&sdp->sd_rindex_spin);
-
-       list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) {
-               if (rgrp_contains_block(rgd, blk)) {
-                       list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
+       newn = &sdp->sd_rindex_tree.rb_node;
+       while (*newn) {
+               cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
+               if (blk < cur->rd_addr)
+                       newn = &((*newn)->rb_left);
+               else if (blk >= cur->rd_data0 + cur->rd_data)
+                       newn = &((*newn)->rb_right);
+               else {
                        spin_unlock(&sdp->sd_rindex_spin);
-                       return rgd;
+                       return cur;
                }
        }
-
        spin_unlock(&sdp->sd_rindex_spin);
 
        return NULL;
@@ -354,8 +359,15 @@ struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
 
 struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
 {
-       gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list));
-       return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);
+       const struct rb_node *n;
+       struct gfs2_rgrpd *rgd;
+
+       spin_lock(&sdp->sd_rindex_spin);
+       n = rb_first(&sdp->sd_rindex_tree);
+       rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
+       spin_unlock(&sdp->sd_rindex_spin);
+
+       return rgd;
 }
 
 /**
@@ -367,47 +379,60 @@ struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
 
 struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
 {
-       if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list)
+       struct gfs2_sbd *sdp = rgd->rd_sbd;
+       const struct rb_node *n;
+
+       spin_lock(&sdp->sd_rindex_spin);
+       n = rb_next(&rgd->rd_node);
+       if (n == NULL)
+               n = rb_first(&sdp->sd_rindex_tree);
+
+       if (unlikely(&rgd->rd_node == n)) {
+               spin_unlock(&sdp->sd_rindex_spin);
                return NULL;
-       return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);
+       }
+       rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
+       spin_unlock(&sdp->sd_rindex_spin);
+       return rgd;
 }
 
-static void clear_rgrpdi(struct gfs2_sbd *sdp)
+void gfs2_free_clones(struct gfs2_rgrpd *rgd)
 {
-       struct list_head *head;
+       int x;
+
+       for (x = 0; x < rgd->rd_length; x++) {
+               struct gfs2_bitmap *bi = rgd->rd_bits + x;
+               kfree(bi->bi_clone);
+               bi->bi_clone = NULL;
+       }
+}
+
+void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
+{
+       struct rb_node *n;
        struct gfs2_rgrpd *rgd;
        struct gfs2_glock *gl;
 
-       spin_lock(&sdp->sd_rindex_spin);
-       sdp->sd_rindex_forward = NULL;
-       spin_unlock(&sdp->sd_rindex_spin);
-
-       head = &sdp->sd_rindex_list;
-       while (!list_empty(head)) {
-               rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
+       while ((n = rb_first(&sdp->sd_rindex_tree))) {
+               rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
                gl = rgd->rd_gl;
 
-               list_del(&rgd->rd_list);
-               list_del(&rgd->rd_list_mru);
+               rb_erase(n, &sdp->sd_rindex_tree);
 
                if (gl) {
+                       spin_lock(&gl->gl_spin);
                        gl->gl_object = NULL;
+                       spin_unlock(&gl->gl_spin);
                        gfs2_glock_add_to_lru(gl);
                        gfs2_glock_put(gl);
                }
 
+               gfs2_free_clones(rgd);
                kfree(rgd->rd_bits);
                kmem_cache_free(gfs2_rgrpd_cachep, rgd);
        }
 }
 
-void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
-{
-       mutex_lock(&sdp->sd_rindex_mutex);
-       clear_rgrpdi(sdp);
-       mutex_unlock(&sdp->sd_rindex_mutex);
-}
-
 static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd)
 {
        printk(KERN_INFO "  ri_addr = %llu\n", (unsigned long long)rgd->rd_addr);
@@ -524,22 +549,34 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
        return total_data;
 }
 
-static void gfs2_rindex_in(struct gfs2_rgrpd *rgd, const void *buf)
+static void rgd_insert(struct gfs2_rgrpd *rgd)
 {
-       const struct gfs2_rindex *str = buf;
+       struct gfs2_sbd *sdp = rgd->rd_sbd;
+       struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
+
+       /* Figure out where to put new node */
+       while (*newn) {
+               struct gfs2_rgrpd *cur = rb_entry(*newn, struct gfs2_rgrpd,
+                                                 rd_node);
+
+               parent = *newn;
+               if (rgd->rd_addr < cur->rd_addr)
+                       newn = &((*newn)->rb_left);
+               else if (rgd->rd_addr > cur->rd_addr)
+                       newn = &((*newn)->rb_right);
+               else
+                       return;
+       }
 
-       rgd->rd_addr = be64_to_cpu(str->ri_addr);
-       rgd->rd_length = be32_to_cpu(str->ri_length);
-       rgd->rd_data0 = be64_to_cpu(str->ri_data0);
-       rgd->rd_data = be32_to_cpu(str->ri_data);
-       rgd->rd_bitbytes = be32_to_cpu(str->ri_bitbytes);
+       rb_link_node(&rgd->rd_node, parent, newn);
+       rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
 }
 
 /**
  * read_rindex_entry - Pull in a new resource index entry from the disk
  * @gl: The glock covering the rindex inode
  *
- * Returns: 0 on success, error code otherwise
+ * Returns: 0 on success, > 0 on EOF, error code otherwise
  */
 
 static int read_rindex_entry(struct gfs2_inode *ip,
@@ -547,44 +584,53 @@ static int read_rindex_entry(struct gfs2_inode *ip,
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
-       char buf[sizeof(struct gfs2_rindex)];
+       struct gfs2_rindex buf;
        int error;
        struct gfs2_rgrpd *rgd;
 
-       error = gfs2_internal_read(ip, ra_state, buf, &pos,
+       if (pos >= i_size_read(&ip->i_inode))
+               return 1;
+
+       error = gfs2_internal_read(ip, ra_state, (char *)&buf, &pos,
                                   sizeof(struct gfs2_rindex));
-       if (!error)
-               return 0;
-       if (error != sizeof(struct gfs2_rindex)) {
-               if (error > 0)
-                       error = -EIO;
-               return error;
-       }
+
+       if (error != sizeof(struct gfs2_rindex))
+               return (error == 0) ? 1 : error;
 
        rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS);
        error = -ENOMEM;
        if (!rgd)
                return error;
 
-       mutex_init(&rgd->rd_mutex);
-       lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
        rgd->rd_sbd = sdp;
+       rgd->rd_addr = be64_to_cpu(buf.ri_addr);
+       rgd->rd_length = be32_to_cpu(buf.ri_length);
+       rgd->rd_data0 = be64_to_cpu(buf.ri_data0);
+       rgd->rd_data = be32_to_cpu(buf.ri_data);
+       rgd->rd_bitbytes = be32_to_cpu(buf.ri_bitbytes);
 
-       list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list);
-       list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
-
-       gfs2_rindex_in(rgd, buf);
        error = compute_bitstructs(rgd);
        if (error)
-               return error;
+               goto fail;
 
        error = gfs2_glock_get(sdp, rgd->rd_addr,
                               &gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
        if (error)
-               return error;
+               goto fail;
 
        rgd->rd_gl->gl_object = rgd;
        rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
+       if (rgd->rd_data > sdp->sd_max_rg_data)
+               sdp->sd_max_rg_data = rgd->rd_data;
+       spin_lock(&sdp->sd_rindex_spin);
+       rgd_insert(rgd);
+       sdp->sd_rgrps++;
+       spin_unlock(&sdp->sd_rindex_spin);
+       return error;
+
+fail:
+       kfree(rgd->rd_bits);
+       kmem_cache_free(gfs2_rgrpd_cachep, rgd);
        return error;
 }
 
@@ -595,40 +641,28 @@ static int read_rindex_entry(struct gfs2_inode *ip,
  * Returns: 0 on successful update, error code otherwise
  */
 
-int gfs2_ri_update(struct gfs2_inode *ip)
+static int gfs2_ri_update(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct inode *inode = &ip->i_inode;
        struct file_ra_state ra_state;
-       u64 rgrp_count = i_size_read(inode);
-       struct gfs2_rgrpd *rgd;
-       unsigned int max_data = 0;
        int error;
 
-       do_div(rgrp_count, sizeof(struct gfs2_rindex));
-       clear_rgrpdi(sdp);
-
        file_ra_state_init(&ra_state, inode->i_mapping);
-       for (sdp->sd_rgrps = 0; sdp->sd_rgrps < rgrp_count; sdp->sd_rgrps++) {
+       do {
                error = read_rindex_entry(ip, &ra_state);
-               if (error) {
-                       clear_rgrpdi(sdp);
-                       return error;
-               }
-       }
+       } while (error == 0);
+
+       if (error < 0)
+               return error;
 
-       list_for_each_entry(rgd, &sdp->sd_rindex_list, rd_list)
-               if (rgd->rd_data > max_data)
-                       max_data = rgd->rd_data;
-       sdp->sd_max_rg_data = max_data;
        sdp->sd_rindex_uptodate = 1;
        return 0;
 }
 
 /**
- * gfs2_rindex_hold - Grab a lock on the rindex
+ * gfs2_rindex_update - Update the rindex if required
  * @sdp: The GFS2 superblock
- * @ri_gh: the glock holder
  *
  * We grab a lock on the rindex inode to make sure that it doesn't
  * change whilst we are performing an operation. We keep this lock
@@ -640,30 +674,29 @@ int gfs2_ri_update(struct gfs2_inode *ip)
  * special file, which might have been updated if someone expanded the
  * filesystem (via gfs2_grow utility), which adds new resource groups.
  *
- * Returns: 0 on success, error code otherwise
+ * Returns: 0 on succeess, error code otherwise
  */
 
-int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
+int gfs2_rindex_update(struct gfs2_sbd *sdp)
 {
        struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
        struct gfs2_glock *gl = ip->i_gl;
-       int error;
-
-       error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
-       if (error)
-               return error;
+       struct gfs2_holder ri_gh;
+       int error = 0;
 
        /* Read new copy from disk if we don't have the latest */
        if (!sdp->sd_rindex_uptodate) {
                mutex_lock(&sdp->sd_rindex_mutex);
-               if (!sdp->sd_rindex_uptodate) {
+               error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
+               if (error)
+                       return error;
+               if (!sdp->sd_rindex_uptodate)
                        error = gfs2_ri_update(ip);
-                       if (error)
-                               gfs2_glock_dq_uninit(ri_gh);
-               }
+               gfs2_glock_dq_uninit(&ri_gh);
                mutex_unlock(&sdp->sd_rindex_mutex);
        }
 
+
        return error;
 }
 
@@ -694,7 +727,7 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
 }
 
 /**
- * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
+ * gfs2_rgrp_go_lock - Read in a RG's header and bitmaps
  * @rgd: the struct gfs2_rgrpd describing the RG to read in
  *
  * Read in all of a Resource Group's header and bitmap blocks.
@@ -703,8 +736,9 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
  * Returns: errno
  */
 
-int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
+int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
 {
+       struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
        struct gfs2_sbd *sdp = rgd->rd_sbd;
        struct gfs2_glock *gl = rgd->rd_gl;
        unsigned int length = rgd->rd_length;
@@ -712,17 +746,6 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
        unsigned int x, y;
        int error;
 
-       mutex_lock(&rgd->rd_mutex);
-
-       spin_lock(&sdp->sd_rindex_spin);
-       if (rgd->rd_bh_count) {
-               rgd->rd_bh_count++;
-               spin_unlock(&sdp->sd_rindex_spin);
-               mutex_unlock(&rgd->rd_mutex);
-               return 0;
-       }
-       spin_unlock(&sdp->sd_rindex_spin);
-
        for (x = 0; x < length; x++) {
                bi = rgd->rd_bits + x;
                error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh);
@@ -747,15 +770,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
                        clear_bit(GBF_FULL, &rgd->rd_bits[x].bi_flags);
                gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data);
                rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
+               rgd->rd_free_clone = rgd->rd_free;
        }
 
-       spin_lock(&sdp->sd_rindex_spin);
-       rgd->rd_free_clone = rgd->rd_free;
-       rgd->rd_bh_count++;
-       spin_unlock(&sdp->sd_rindex_spin);
-
-       mutex_unlock(&rgd->rd_mutex);
-
        return 0;
 
 fail:
@@ -765,52 +782,32 @@ fail:
                bi->bi_bh = NULL;
                gfs2_assert_warn(sdp, !bi->bi_clone);
        }
-       mutex_unlock(&rgd->rd_mutex);
 
        return error;
 }
 
-void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd)
-{
-       struct gfs2_sbd *sdp = rgd->rd_sbd;
-
-       spin_lock(&sdp->sd_rindex_spin);
-       gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
-       rgd->rd_bh_count++;
-       spin_unlock(&sdp->sd_rindex_spin);
-}
-
 /**
- * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get()
+ * gfs2_rgrp_go_unlock - Release RG bitmaps read in with gfs2_rgrp_bh_get()
  * @rgd: the struct gfs2_rgrpd describing the RG to read in
  *
  */
 
-void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd)
+void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
 {
-       struct gfs2_sbd *sdp = rgd->rd_sbd;
+       struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
        int x, length = rgd->rd_length;
 
-       spin_lock(&sdp->sd_rindex_spin);
-       gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
-       if (--rgd->rd_bh_count) {
-               spin_unlock(&sdp->sd_rindex_spin);
-               return;
-       }
-
        for (x = 0; x < length; x++) {
                struct gfs2_bitmap *bi = rgd->rd_bits + x;
-               kfree(bi->bi_clone);
-               bi->bi_clone = NULL;
                brelse(bi->bi_bh);
                bi->bi_bh = NULL;
        }
 
-       spin_unlock(&sdp->sd_rindex_spin);
 }
 
-static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
-                                   const struct gfs2_bitmap *bi)
+void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+                            struct buffer_head *bh,
+                            const struct gfs2_bitmap *bi)
 {
        struct super_block *sb = sdp->sd_vfs;
        struct block_device *bdev = sb->s_bdev;
@@ -823,7 +820,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
        unsigned int x;
 
        for (x = 0; x < bi->bi_len; x++) {
-               const u8 *orig = bi->bi_bh->b_data + bi->bi_offset + x;
+               const u8 *orig = bh->b_data + bi->bi_offset + x;
                const u8 *clone = bi->bi_clone + bi->bi_offset + x;
                u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
                diff &= 0x55;
@@ -862,28 +859,6 @@ fail:
        sdp->sd_args.ar_discard = 0;
 }
 
-void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
-{
-       struct gfs2_sbd *sdp = rgd->rd_sbd;
-       unsigned int length = rgd->rd_length;
-       unsigned int x;
-
-       for (x = 0; x < length; x++) {
-               struct gfs2_bitmap *bi = rgd->rd_bits + x;
-               if (!bi->bi_clone)
-                       continue;
-               if (sdp->sd_args.ar_discard)
-                       gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi);
-               clear_bit(GBF_FULL, &bi->bi_flags);
-               memcpy(bi->bi_clone + bi->bi_offset,
-                      bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
-       }
-
-       spin_lock(&sdp->sd_rindex_spin);
-       rgd->rd_free_clone = rgd->rd_free;
-       spin_unlock(&sdp->sd_rindex_spin);
-}
-
 /**
  * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode
  * @ip: the incore GFS2 inode structure
@@ -893,38 +868,35 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
 
 struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
 {
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       int error;
        BUG_ON(ip->i_alloc != NULL);
        ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_NOFS);
+       error = gfs2_rindex_update(sdp);
+       if (error)
+               fs_warn(sdp, "rindex update returns %d\n", error);
        return ip->i_alloc;
 }
 
 /**
  * try_rgrp_fit - See if a given reservation will fit in a given RG
  * @rgd: the RG data
- * @al: the struct gfs2_alloc structure describing the reservation
+ * @ip: the inode
  *
  * If there's room for the requested blocks to be allocated from the RG:
- *   Sets the $al_rgd field in @al.
  *
  * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
  */
 
-static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
+static int try_rgrp_fit(const struct gfs2_rgrpd *rgd, const struct gfs2_inode *ip)
 {
-       struct gfs2_sbd *sdp = rgd->rd_sbd;
-       int ret = 0;
+       const struct gfs2_alloc *al = ip->i_alloc;
 
        if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
                return 0;
-
-       spin_lock(&sdp->sd_rindex_spin);
-       if (rgd->rd_free_clone >= al->al_requested) {
-               al->al_rgd = rgd;
-               ret = 1;
-       }
-       spin_unlock(&sdp->sd_rindex_spin);
-
-       return ret;
+       if (rgd->rd_free_clone >= al->al_requested)
+               return 1;
+       return 0;
 }
 
 /**
@@ -991,76 +963,6 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
        return;
 }
 
-/**
- * recent_rgrp_next - get next RG from "recent" list
- * @cur_rgd: current rgrp
- *
- * Returns: The next rgrp in the recent list
- */
-
-static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd)
-{
-       struct gfs2_sbd *sdp = cur_rgd->rd_sbd;
-       struct list_head *head;
-       struct gfs2_rgrpd *rgd;
-
-       spin_lock(&sdp->sd_rindex_spin);
-       head = &sdp->sd_rindex_mru_list;
-       if (unlikely(cur_rgd->rd_list_mru.next == head)) {
-               spin_unlock(&sdp->sd_rindex_spin);
-               return NULL;
-       }
-       rgd = list_entry(cur_rgd->rd_list_mru.next, struct gfs2_rgrpd, rd_list_mru);
-       spin_unlock(&sdp->sd_rindex_spin);
-       return rgd;
-}
-
-/**
- * forward_rgrp_get - get an rgrp to try next from full list
- * @sdp: The GFS2 superblock
- *
- * Returns: The rgrp to try next
- */
-
-static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp)
-{
-       struct gfs2_rgrpd *rgd;
-       unsigned int journals = gfs2_jindex_size(sdp);
-       unsigned int rg = 0, x;
-
-       spin_lock(&sdp->sd_rindex_spin);
-
-       rgd = sdp->sd_rindex_forward;
-       if (!rgd) {
-               if (sdp->sd_rgrps >= journals)
-                       rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;
-
-               for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;
-                    x++, rgd = gfs2_rgrpd_get_next(rgd))
-                       /* Do Nothing */;
-
-               sdp->sd_rindex_forward = rgd;
-       }
-
-       spin_unlock(&sdp->sd_rindex_spin);
-
-       return rgd;
-}
-
-/**
- * forward_rgrp_set - set the forward rgrp pointer
- * @sdp: the filesystem
- * @rgd: The new forward rgrp
- *
- */
-
-static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
-{
-       spin_lock(&sdp->sd_rindex_spin);
-       sdp->sd_rindex_forward = rgd;
-       spin_unlock(&sdp->sd_rindex_spin);
-}
-
 /**
  * get_local_rgrp - Choose and lock a rgrp for allocation
  * @ip: the inode to reserve space for
@@ -1076,14 +978,18 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrpd *rgd, *begin = NULL;
        struct gfs2_alloc *al = ip->i_alloc;
-       int flags = LM_FLAG_TRY;
-       int skipped = 0;
-       int loops = 0;
        int error, rg_locked;
+       int loops = 0;
+
+       if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
+               rgd = begin = ip->i_rgd;
+       else
+               rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
 
-       rgd = gfs2_blk2rgrpd(sdp, ip->i_goal);
+       if (rgd == NULL)
+               return -EBADSLT;
 
-       while (rgd) {
+       while (loops < 3) {
                rg_locked = 0;
 
                if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
@@ -1095,92 +1001,36 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
                }
                switch (error) {
                case 0:
-                       if (try_rgrp_fit(rgd, al))
-                               goto out;
+                       if (try_rgrp_fit(rgd, ip)) {
+                               ip->i_rgd = rgd;
+                               return 0;
+                       }
                        if (rgd->rd_flags & GFS2_RDF_CHECK)
                                try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
                        if (!rg_locked)
                                gfs2_glock_dq_uninit(&al->al_rgd_gh);
                        /* fall through */
                case GLR_TRYFAILED:
-                       rgd = recent_rgrp_next(rgd);
-                       break;
-
-               default:
-                       return error;
-               }
-       }
-
-       /* Go through full list of rgrps */
-
-       begin = rgd = forward_rgrp_get(sdp);
-
-       for (;;) {
-               rg_locked = 0;
-
-               if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
-                       rg_locked = 1;
-                       error = 0;
-               } else {
-                       error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
-                                                  &al->al_rgd_gh);
-               }
-               switch (error) {
-               case 0:
-                       if (try_rgrp_fit(rgd, al))
-                               goto out;
-                       if (rgd->rd_flags & GFS2_RDF_CHECK)
-                               try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
-                       if (!rg_locked)
-                               gfs2_glock_dq_uninit(&al->al_rgd_gh);
-                       break;
-
-               case GLR_TRYFAILED:
-                       skipped++;
+                       rgd = gfs2_rgrpd_get_next(rgd);
+                       if (rgd == begin)
+                               loops++;
                        break;
-
                default:
                        return error;
                }
-
-               rgd = gfs2_rgrpd_get_next(rgd);
-               if (!rgd)
-                       rgd = gfs2_rgrpd_get_first(sdp);
-
-               if (rgd == begin) {
-                       if (++loops >= 3)
-                               return -ENOSPC;
-                       if (!skipped)
-                               loops++;
-                       flags = 0;
-                       if (loops == 2)
-                               gfs2_log_flush(sdp, NULL);
-               }
        }
 
-out:
-       if (begin) {
-               spin_lock(&sdp->sd_rindex_spin);
-               list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
-               spin_unlock(&sdp->sd_rindex_spin);
-               rgd = gfs2_rgrpd_get_next(rgd);
-               if (!rgd)
-                       rgd = gfs2_rgrpd_get_first(sdp);
-               forward_rgrp_set(sdp, rgd);
-       }
-
-       return 0;
+       return -ENOSPC;
 }
 
 /**
- * gfs2_inplace_reserve_i - Reserve space in the filesystem
+ * gfs2_inplace_reserve - Reserve space in the filesystem
  * @ip: the inode to reserve space for
  *
  * Returns: errno
  */
 
-int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
-                          char *file, unsigned int line)
+int gfs2_inplace_reserve(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = ip->i_alloc;
@@ -1191,45 +1041,22 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
        if (gfs2_assert_warn(sdp, al->al_requested))
                return -EINVAL;
 
-       if (hold_rindex) {
-               /* We need to hold the rindex unless the inode we're using is
-                  the rindex itself, in which case it's already held. */
-               if (ip != GFS2_I(sdp->sd_rindex))
-                       error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
-               else if (!sdp->sd_rgrps) /* We may not have the rindex read
-                                           in, so: */
-                       error = gfs2_ri_update(ip);
-               if (error)
-                       return error;
-       }
-
-try_again:
        do {
                error = get_local_rgrp(ip, &last_unlinked);
-               /* If there is no space, flushing the log may release some */
-               if (error) {
-                       if (ip == GFS2_I(sdp->sd_rindex) &&
-                           !sdp->sd_rindex_uptodate) {
-                               error = gfs2_ri_update(ip);
-                               if (error)
-                                       return error;
-                               goto try_again;
-                       }
-                       gfs2_log_flush(sdp, NULL);
+               if (error != -ENOSPC)
+                       break;
+               /* Check that fs hasn't grown if writing to rindex */
+               if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
+                       error = gfs2_ri_update(ip);
+                       if (error)
+                               break;
+                       continue;
                }
-       } while (error && tries++ < 3);
-
-       if (error) {
-               if (hold_rindex && ip != GFS2_I(sdp->sd_rindex))
-                       gfs2_glock_dq_uninit(&al->al_ri_gh);
-               return error;
-       }
-
-       /* no error, so we have the rgrp set in the inode's allocation. */
-       al->al_file = file;
-       al->al_line = line;
+               /* Flushing the log may release space */
+               gfs2_log_flush(sdp, NULL);
+       } while (tries++ < 3);
 
-       return 0;
+       return error;
 }
 
 /**
@@ -1241,20 +1068,10 @@ try_again:
 
 void gfs2_inplace_release(struct gfs2_inode *ip)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = ip->i_alloc;
 
-       if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
-               fs_warn(sdp, "al_alloced = %u, al_requested = %u "
-                            "al_file = %s, al_line = %u\n",
-                            al->al_alloced, al->al_requested, al->al_file,
-                            al->al_line);
-
-       al->al_rgd = NULL;
        if (al->al_rgd_gh.gh_gl)
                gfs2_glock_dq_uninit(&al->al_rgd_gh);
-       if (ip != GFS2_I(sdp->sd_rindex) && al->al_ri_gh.gh_gl)
-               gfs2_glock_dq_uninit(&al->al_ri_gh);
 }
 
 /**
@@ -1352,6 +1169,7 @@ do_search:
                /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
                   bitmaps, so we must search the originals for that. */
                buffer = bi->bi_bh->b_data + bi->bi_offset;
+               WARN_ON(!buffer_uptodate(bi->bi_bh));
                if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
                        buffer = bi->bi_clone + bi->bi_offset;
 
@@ -1371,6 +1189,7 @@ skip:
 
        if (blk == BFITNOENT)
                return blk;
+
        *n = 1;
        if (old_state == new_state)
                goto out;
@@ -1503,7 +1322,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
        if (al == NULL)
                return -ECANCELED;
 
-       rgd = al->al_rgd;
+       rgd = ip->i_rgd;
 
        if (rgrp_contains_block(rgd, ip->i_goal))
                goal = ip->i_goal - rgd->rd_data0;
@@ -1518,7 +1337,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
 
        rgd->rd_last_alloc = blk;
        block = rgd->rd_data0 + blk;
-       ip->i_goal = block;
+       ip->i_goal = block + *n - 1;
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error == 0) {
                struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
@@ -1539,9 +1358,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
        gfs2_statfs_change(sdp, 0, -(s64)*n, 0);
        gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid);
 
-       spin_lock(&sdp->sd_rindex_spin);
        rgd->rd_free_clone -= *n;
-       spin_unlock(&sdp->sd_rindex_spin);
        trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED);
        *bn = block;
        return 0;
@@ -1564,7 +1381,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_alloc *al = dip->i_alloc;
-       struct gfs2_rgrpd *rgd = al->al_rgd;
+       struct gfs2_rgrpd *rgd = dip->i_rgd;
        u32 blk;
        u64 block;
        unsigned int n = 1;
@@ -1594,9 +1411,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
        gfs2_statfs_change(sdp, 0, -1, +1);
        gfs2_trans_add_unrevoke(sdp, block, 1);
 
-       spin_lock(&sdp->sd_rindex_spin);
        rgd->rd_free_clone--;
-       spin_unlock(&sdp->sd_rindex_spin);
        trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
        *bn = block;
        return 0;
@@ -1629,8 +1444,6 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
        gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
 
-       gfs2_trans_add_rg(rgd);
-
        /* Directories keep their data in the metadata address space */
        if (meta || ip->i_depth)
                gfs2_meta_wipe(ip, bstart, blen);
@@ -1666,7 +1479,6 @@ void gfs2_unlink_di(struct inode *inode)
        trace_gfs2_block_alloc(ip, blkno, 1, GFS2_BLKST_UNLINKED);
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
        gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
-       gfs2_trans_add_rg(rgd);
 }
 
 static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
@@ -1688,7 +1500,6 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
        gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
 
        gfs2_statfs_change(sdp, 0, +1, -1);
-       gfs2_trans_add_rg(rgd);
 }
 
 
@@ -1714,41 +1525,33 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
 int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
 {
        struct gfs2_rgrpd *rgd;
-       struct gfs2_holder ri_gh, rgd_gh;
-       struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
-       int ri_locked = 0;
+       struct gfs2_holder rgd_gh;
        int error;
 
-       if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
-               error = gfs2_rindex_hold(sdp, &ri_gh);
-               if (error)
-                       goto fail;
-               ri_locked = 1;
-       }
+       error = gfs2_rindex_update(sdp);
+       if (error)
+               return error;
 
        error = -EINVAL;
        rgd = gfs2_blk2rgrpd(sdp, no_addr);
        if (!rgd)
-               goto fail_rindex;
+               goto fail;
 
        error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
        if (error)
-               goto fail_rindex;
+               goto fail;
 
        if (gfs2_get_block_type(rgd, no_addr) != type)
                error = -ESTALE;
 
        gfs2_glock_dq_uninit(&rgd_gh);
-fail_rindex:
-       if (ri_locked)
-               gfs2_glock_dq_uninit(&ri_gh);
 fail:
        return error;
 }
 
 /**
  * gfs2_rlist_add - add a RG to a list of RGs
- * @sdp: the filesystem
+ * @ip: the inode
  * @rlist: the list of resource groups
  * @block: the block
  *
@@ -1758,9 +1561,10 @@ fail:
  *
  */
 
-void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
                    u64 block)
 {
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrpd *rgd;
        struct gfs2_rgrpd **tmp;
        unsigned int new_space;
@@ -1769,12 +1573,15 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
        if (gfs2_assert_warn(sdp, !rlist->rl_ghs))
                return;
 
-       rgd = gfs2_blk2rgrpd(sdp, block);
+       if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
+               rgd = ip->i_rgd;
+       else
+               rgd = gfs2_blk2rgrpd(sdp, block);
        if (!rgd) {
-               if (gfs2_consist(sdp))
-                       fs_err(sdp, "block = %llu\n", (unsigned long long)block);
+               fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
                return;
        }
+       ip->i_rgd = rgd;
 
        for (x = 0; x < rlist->rl_rgrps; x++)
                if (rlist->rl_rgd[x] == rgd)
index d253f9a..cf5c501 100644 (file)
@@ -18,18 +18,15 @@ struct gfs2_holder;
 
 extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
 
-struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
-struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
-struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
+extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
+extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
+extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
 
 extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
-extern int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
-
-extern int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
-extern void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
-extern void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
-
-extern void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
+extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
+extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
+extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
+extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
 
 extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
 static inline void gfs2_alloc_put(struct gfs2_inode *ip)
@@ -39,16 +36,9 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
        ip->i_alloc = NULL;
 }
 
-extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
-                                 char *file, unsigned int line);
-#define gfs2_inplace_reserve(ip) \
-       gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__)
-#define gfs2_inplace_reserve_ri(ip) \
-       gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__)
-
+extern int gfs2_inplace_reserve(struct gfs2_inode *ip);
 extern void gfs2_inplace_release(struct gfs2_inode *ip);
 
-extern int gfs2_ri_update(struct gfs2_inode *ip);
 extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
 extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
 
@@ -66,11 +56,14 @@ struct gfs2_rgrp_list {
        struct gfs2_holder *rl_ghs;
 };
 
-extern void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
                           u64 block);
 extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
 extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
 extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
 extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
+extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+                                   struct buffer_head *bh,
+                                   const struct gfs2_bitmap *bi);
 
 #endif /* __RGRP_DOT_H__ */
index b7beadd..71e4209 100644 (file)
@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
        struct backing_dev_info *bdi = metamapping->backing_dev_info;
-       struct gfs2_holder gh;
+       int ret = 0;
+
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+       if (bdi->dirty_exceeded)
+               gfs2_ail1_flush(sdp, wbc);
+       else
+               filemap_fdatawrite(metamapping);
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               ret = filemap_fdatawait(metamapping);
+       if (ret)
+               mark_inode_dirty_sync(inode);
+       return ret;
+}
+
+/**
+ * gfs2_dirty_inode - check for atime updates
+ * @inode: The inode in question
+ * @flags: The type of dirty
+ *
+ * Unfortunately it can be called under any combination of inode
+ * glock and transaction lock, so we have to check carefully.
+ *
+ * At the moment this deals only with atime - it should be possible
+ * to expand that role in future, once a review of the locking has
+ * been carried out.
+ */
+
+static void gfs2_dirty_inode(struct inode *inode, int flags)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct buffer_head *bh;
-       struct timespec atime;
-       struct gfs2_dinode *di;
-       int ret = -EAGAIN;
-       int unlock_required = 0;
-
-       /* Skip timestamp update, if this is from a memalloc */
-       if (current->flags & PF_MEMALLOC)
-               goto do_flush;
+       struct gfs2_holder gh;
+       int need_unlock = 0;
+       int need_endtrans = 0;
+       int ret;
+
+       if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
+               return;
+
        if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
                ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-               if (ret)
-                       goto do_flush;
-               unlock_required = 1;
+               if (ret) {
+                       fs_err(sdp, "dirty_inode: glock %d\n", ret);
+                       return;
+               }
+               need_unlock = 1;
        }
-       ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
-       if (ret)
-               goto do_unlock;
+
+       if (current->journal_info == NULL) {
+               ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
+               if (ret) {
+                       fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret);
+                       goto out;
+               }
+               need_endtrans = 1;
+       }
+
        ret = gfs2_meta_inode_buffer(ip, &bh);
        if (ret == 0) {
-               di = (struct gfs2_dinode *)bh->b_data;
-               atime.tv_sec = be64_to_cpu(di->di_atime);
-               atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
-               if (timespec_compare(&inode->i_atime, &atime) > 0) {
-                       gfs2_trans_add_bh(ip->i_gl, bh, 1);
-                       gfs2_dinode_out(ip, bh->b_data);
-               }
+               gfs2_trans_add_bh(ip->i_gl, bh, 1);
+               gfs2_dinode_out(ip, bh->b_data);
                brelse(bh);
        }
-       gfs2_trans_end(sdp);
-do_unlock:
-       if (unlock_required)
+
+       if (need_endtrans)
+               gfs2_trans_end(sdp);
+out:
+       if (need_unlock)
                gfs2_glock_dq_uninit(&gh);
-do_flush:
-       if (wbc->sync_mode == WB_SYNC_ALL)
-               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
-       filemap_fdatawrite(metamapping);
-       if (bdi->dirty_exceeded)
-               gfs2_ail1_flush(sdp, wbc);
-       if (!ret && (wbc->sync_mode == WB_SYNC_ALL))
-               ret = filemap_fdatawait(metamapping);
-       if (ret)
-               mark_inode_dirty_sync(inode);
-       return ret;
 }
 
 /**
@@ -1011,7 +1037,6 @@ static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
 
 static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
 {
-       struct gfs2_holder ri_gh;
        struct gfs2_rgrpd *rgd_next;
        struct gfs2_holder *gha, *gh;
        unsigned int slots = 64;
@@ -1024,10 +1049,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
        if (!gha)
                return -ENOMEM;
 
-       error = gfs2_rindex_hold(sdp, &ri_gh);
-       if (error)
-               goto out;
-
        rgd_next = gfs2_rgrpd_get_first(sdp);
 
        for (;;) {
@@ -1070,9 +1091,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
                yield();
        }
 
-       gfs2_glock_dq_uninit(&ri_gh);
-
-out:
        kfree(gha);
        return error;
 }
@@ -1124,6 +1142,10 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct gfs2_statfs_change_host sc;
        int error;
 
+       error = gfs2_rindex_update(sdp);
+       if (error)
+               return error;
+
        if (gfs2_tune_get(sdp, gt_statfs_slow))
                error = gfs2_statfs_slow(sdp, &sc);
        else
@@ -1394,21 +1416,17 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
        if (error)
                goto out;
 
-       error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
-       if (error)
-               goto out_qs;
-
        rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
        if (!rgd) {
                gfs2_consist_inode(ip);
                error = -EIO;
-               goto out_rindex_relse;
+               goto out_qs;
        }
 
        error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
                                   &al->al_rgd_gh);
        if (error)
-               goto out_rindex_relse;
+               goto out_qs;
 
        error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA,
                                 sdp->sd_jdesc->jd_blocks);
@@ -1423,8 +1441,6 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
 
 out_rg_gunlock:
        gfs2_glock_dq_uninit(&al->al_rgd_gh);
-out_rindex_relse:
-       gfs2_glock_dq_uninit(&al->al_ri_gh);
 out_qs:
        gfs2_quota_unhold(ip);
 out:
@@ -1471,9 +1487,11 @@ static void gfs2_evict_inode(struct inode *inode)
                goto out;
        }
 
-       error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
-       if (error)
-               goto out_truncate;
+       if (!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
+               error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
+               if (error)
+                       goto out_truncate;
+       }
 
        if (test_bit(GIF_INVALID, &ip->i_flags)) {
                error = gfs2_inode_refresh(ip);
@@ -1513,6 +1531,10 @@ static void gfs2_evict_inode(struct inode *inode)
        goto out_unlock;
 
 out_truncate:
+       gfs2_log_flush(sdp, ip->i_gl);
+       write_inode_now(inode, 1);
+       gfs2_ail_flush(ip->i_gl, 0);
+
        /* Case 2 starts here */
        error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
        if (error)
@@ -1552,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
        if (ip) {
                ip->i_flags = 0;
                ip->i_gl = NULL;
+               ip->i_rgd = NULL;
        }
        return &ip->i_inode;
 }
@@ -1572,6 +1595,7 @@ const struct super_operations gfs2_super_ops = {
        .alloc_inode            = gfs2_alloc_inode,
        .destroy_inode          = gfs2_destroy_inode,
        .write_inode            = gfs2_write_inode,
+       .dirty_inode            = gfs2_dirty_inode,
        .evict_inode            = gfs2_evict_inode,
        .put_super              = gfs2_put_super,
        .sync_fs                = gfs2_sync_fs,
index 9ec73a8..86ac75d 100644 (file)
@@ -185,8 +185,3 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
        gfs2_log_unlock(sdp);
 }
 
-void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
-{
-       lops_add(rgd->rd_sbd, &rgd->rd_le);
-}
-
index fb56b78..f8f101e 100644 (file)
@@ -28,20 +28,20 @@ struct gfs2_glock;
 
 /* reserve either the number of blocks to be allocated plus the rg header
  * block, or all of the blocks in the rg, whichever is smaller */
-static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al)
+static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
 {
-       return (al->al_requested < al->al_rgd->rd_length)?
-              al->al_requested + 1 : al->al_rgd->rd_length;
+       const struct gfs2_alloc *al = ip->i_alloc;
+       if (al->al_requested < ip->i_rgd->rd_length)
+               return al->al_requested + 1;
+       return ip->i_rgd->rd_length;
 }
 
-int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
-                    unsigned int revokes);
+extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+                           unsigned int revokes);
 
-void gfs2_trans_end(struct gfs2_sbd *sdp);
-
-void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
-void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
-void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
+extern void gfs2_trans_end(struct gfs2_sbd *sdp);
+extern void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
+extern void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
+extern void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
 
 #endif /* __TRANS_DOT_H__ */
index 439b61c..71d7bf8 100644 (file)
@@ -332,15 +332,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
        if (error)
                goto out_alloc;
 
-       error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
-       if (error)
-               goto out_quota;
-
        error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
 
-       gfs2_glock_dq_uninit(&al->al_ri_gh);
-
-out_quota:
        gfs2_quota_unhold(ip);
 out_alloc:
        gfs2_alloc_put(ip);
@@ -734,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
                goto out_gunlock_q;
 
        error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
-                                blks + gfs2_rg_blocks(al) +
+                                blks + gfs2_rg_blocks(ip) +
                                 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
        if (error)
                goto out_ipres;
@@ -1296,7 +1289,8 @@ fail:
 
 int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct inode *inode = &ip->i_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct gfs2_ea_location el;
        int error;
 
@@ -1319,7 +1313,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
        if (error)
                return error;
 
-       error = gfs2_setattr_simple(ip, attr);
+       error = gfs2_setattr_simple(inode, attr);
        gfs2_trans_end(sdp);
        return error;
 }
@@ -1362,14 +1356,14 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
                        blen++;
                else {
                        if (bstart)
-                               gfs2_rlist_add(sdp, &rlist, bstart);
+                               gfs2_rlist_add(ip, &rlist, bstart);
                        bstart = bn;
                        blen = 1;
                }
                blks++;
        }
        if (bstart)
-               gfs2_rlist_add(sdp, &rlist, bstart);
+               gfs2_rlist_add(ip, &rlist, bstart);
        else
                goto out;
 
@@ -1501,24 +1495,18 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
        if (error)
                goto out_alloc;
 
-       error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
-       if (error)
-               goto out_quota;
-
        error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
        if (error)
-               goto out_rindex;
+               goto out_quota;
 
        if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
                error = ea_dealloc_indirect(ip);
                if (error)
-                       goto out_rindex;
+                       goto out_quota;
        }
 
        error = ea_dealloc_block(ip);
 
-out_rindex:
-       gfs2_glock_dq_uninit(&al->al_ri_gh);
 out_quota:
        gfs2_quota_unhold(ip);
 out_alloc: