]> Pileus Git - ~andy/linux/commitdiff
[GFS2] Add generation number
authorSteven Whitehouse <swhiteho@redhat.com>
Tue, 11 Jul 2006 13:46:33 +0000 (09:46 -0400)
committerSteven Whitehouse <swhiteho@redhat.com>
Tue, 11 Jul 2006 13:46:33 +0000 (09:46 -0400)
This adds a generation number for the eventual use of NFS to the
ondisk inode. Its backward compatible with the current code since
it doesn't really matter what the generation number is to start with,
and indeed since its set to zero, due to it being taken from padding
in both the inode and rgrp header, it should be fine.

The eventual plan is to use this rather than no_formal_ino in the
NFS filehandles. At that point no_formal_ino will be unused.

At the same time we also add a releasepages call back to the
"normal" address space for gfs2 inodes. Also I've removed a
one-linrer function thats not required any more.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/inode.c
fs/gfs2/meta_io.c
fs/gfs2/ondisk.c
fs/gfs2/ops_address.c
fs/gfs2/ops_address.h
fs/gfs2/ops_file.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
include/linux/gfs2_ondisk.h

index f4c48395208a0be24e14ebf99a2d688d71bc176d..22ca3b5ddaea06c30322dc3084b7af9ac3e10ae5 100644 (file)
 #include "util.h"
 
 /**
- * inode_attr_in - Copy attributes from the dinode into the VFS inode
+ * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
  * @ip: The GFS2 inode (with embedded disk inode data)
  * @inode:  The Linux VFS inode
  *
  */
 
-static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode)
+void gfs2_inode_attr_in(struct gfs2_inode *ip)
 {
-       inode->i_ino = ip->i_num.no_formal_ino;
+       struct inode *inode = &ip->i_inode;
+
+       inode->i_ino = ip->i_num.no_addr;
 
        switch (ip->i_di.di_mode & S_IFMT) {
        case S_IFBLK:
@@ -84,18 +86,6 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode)
                inode->i_flags &= ~S_APPEND;
 }
 
-/**
- * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
- * @ip: The GFS2 inode (with embedded disk inode data)
- *
- */
-
-void gfs2_inode_attr_in(struct gfs2_inode *ip)
-{
-       struct inode *inode = &ip->i_inode;
-       inode_attr_in(ip, inode);
-}
-
 /**
  * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode
  * @ip: The GFS2 inode
@@ -621,7 +611,8 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
                *gid = current->fsgid;
 }
 
-static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum)
+static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum,
+                       u64 *generation)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        int error;
@@ -637,14 +628,14 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum)
        if (error)
                goto out_ipreserv;
 
-       inum->no_addr = gfs2_alloc_di(dip);
+       inum->no_addr = gfs2_alloc_di(dip, generation);
 
        gfs2_trans_end(sdp);
 
- out_ipreserv:
+out_ipreserv:
        gfs2_inplace_release(dip);
 
- out:
+out:
        gfs2_alloc_put(dip);
 
        return error;
@@ -662,8 +653,9 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum)
  */
 
 static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
-                       struct gfs2_inum *inum, unsigned int mode,
-                       unsigned int uid, unsigned int gid)
+                       const struct gfs2_inum *inum, unsigned int mode,
+                       unsigned int uid, unsigned int gid,
+                       const u64 *generation)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_dinode *di;
@@ -686,7 +678,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
        di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds());
        di->di_major = di->di_minor = cpu_to_be32(0);
        di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr);
-       di->__pad[0] = di->__pad[1] = 0;
+       di->di_generation = cpu_to_be64(*generation);
        di->di_flags = cpu_to_be32(0);
 
        if (S_ISREG(mode)) {
@@ -717,7 +709,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 }
 
 static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
-                      unsigned int mode, struct gfs2_inum *inum)
+                      unsigned int mode, const struct gfs2_inum *inum,
+                      const u64 *generation)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        unsigned int uid, gid;
@@ -738,7 +731,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
        if (error)
                goto out_quota;
 
-       init_dinode(dip, gl, inum, mode, uid, gid);
+       init_dinode(dip, gl, inum, mode, uid, gid, generation);
        gfs2_quota_change(dip, +1, uid, gid);
        gfs2_trans_end(sdp);
 
@@ -844,6 +837,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_inum inum;
        int error;
+       u64 generation;
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return ERR_PTR(-ENAMETOOLONG);
@@ -861,7 +855,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        if (error)
                goto fail_gunlock;
 
-       error = alloc_dinode(dip, &inum);
+       error = alloc_dinode(dip, &inum, &generation);
        if (error)
                goto fail_gunlock;
 
@@ -893,7 +887,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
                        goto fail_gunlock;
        }
 
-       error = make_dinode(dip, ghs[1].gh_gl, mode, &inum);
+       error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation);
        if (error)
                goto fail_gunlock2;
 
index ddcd4dc1081d53437a79a146fb243d594df025c6..cad44fd70d67b832d165637d9c47705d42dda6f3 100644 (file)
@@ -31,6 +31,7 @@
 #include "rgrp.h"
 #include "trans.h"
 #include "util.h"
+#include "ops_address.h"
 
 #define buffer_busy(bh) \
 ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned)))
@@ -50,118 +51,9 @@ static int gfs2_aspace_writepage(struct page *page,
        return block_write_full_page(page, aspace_get_block, wbc);
 }
 
-/**
- * stuck_releasepage - We're stuck in gfs2_releasepage().  Print stuff out.
- * @bh: the buffer we're stuck on
- *
- */
-
-static void stuck_releasepage(struct buffer_head *bh)
-{
-       struct inode *inode = bh->b_page->mapping->host;
-       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
-       struct gfs2_bufdata *bd = bh->b_private;
-       struct gfs2_glock *gl;
-
-       fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
-       fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
-               (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
-       fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
-       fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
-
-       if (!bd)
-               return;
-
-       gl = bd->bd_gl;
-
-       fs_warn(sdp, "gl = (%u, %llu)\n", 
-               gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
-
-       fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
-               (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
-               (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
-
-       if (gl->gl_ops == &gfs2_inode_glops) {
-               struct gfs2_inode *ip = gl->gl_object;
-               unsigned int x;
-
-               if (!ip)
-                       return;
-
-               fs_warn(sdp, "ip = %llu %llu\n",
-                       (unsigned long long)ip->i_num.no_formal_ino,
-                       (unsigned long long)ip->i_num.no_addr);
-
-               for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
-                       fs_warn(sdp, "ip->i_cache[%u] = %s\n",
-                               x, (ip->i_cache[x]) ? "!NULL" : "NULL");
-       }
-}
-
-/**
- * gfs2_aspace_releasepage - free the metadata associated with a page
- * @page: the page that's being released
- * @gfp_mask: passed from Linux VFS, ignored by us
- *
- * Call try_to_free_buffers() if the buffers in this page can be
- * released.
- *
- * Returns: 0
- */
-
-static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask)
-{
-       struct inode *aspace = page->mapping->host;
-       struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
-       struct buffer_head *bh, *head;
-       struct gfs2_bufdata *bd;
-       unsigned long t;
-
-       if (!page_has_buffers(page))
-               goto out;
-
-       head = bh = page_buffers(page);
-       do {
-               t = jiffies;
-
-               while (atomic_read(&bh->b_count)) {
-                       if (atomic_read(&aspace->i_writecount)) {
-                               if (time_after_eq(jiffies, t +
-                                   gfs2_tune_get(sdp, gt_stall_secs) * HZ)) {
-                                       stuck_releasepage(bh);
-                                       t = jiffies;
-                               }
-
-                               yield();
-                               continue;
-                       }
-
-                       return 0;
-               }
-
-               gfs2_assert_warn(sdp, !buffer_pinned(bh));
-
-               bd = bh->b_private;
-               if (bd) {
-                       gfs2_assert_warn(sdp, bd->bd_bh == bh);
-                       gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
-                       gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list));
-                       gfs2_assert_warn(sdp, !bd->bd_ail);
-                       kmem_cache_free(gfs2_bufdata_cachep, bd);
-                       bh->b_private = NULL;
-               }
-
-               bh = bh->b_this_page;
-       }
-       while (bh != head);
-
- out:
-       return try_to_free_buffers(page);
-}
-
 static const struct address_space_operations aspace_aops = {
        .writepage = gfs2_aspace_writepage,
-       .releasepage = gfs2_aspace_releasepage,
+       .releasepage = gfs2_releasepage,
 };
 
 /**
index 09154ad7b2706b5c65d1810d7462df314b3b8d6f..39c7f0345fc6cdd2683932fc134abea45c5404d9 100644 (file)
@@ -128,6 +128,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf)
        rg->rg_flags = be32_to_cpu(str->rg_flags);
        rg->rg_free = be32_to_cpu(str->rg_free);
        rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);
+       rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);
 }
 
 void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf)
@@ -138,7 +139,8 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf)
        str->rg_flags = cpu_to_be32(rg->rg_flags);
        str->rg_free = cpu_to_be32(rg->rg_free);
        str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);
-
+       str->__pad = cpu_to_be32(0);
+       str->rg_igeneration = cpu_to_be64(rg->rg_igeneration);
        memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
 }
 
@@ -172,6 +174,7 @@ void gfs2_dinode_in(struct gfs2_dinode *di, char *buf)
 
        di->di_goal_meta = be64_to_cpu(str->di_goal_meta);
        di->di_goal_data = be64_to_cpu(str->di_goal_data);
+       di->di_generation = be64_to_cpu(str->di_generation);
 
        di->di_flags = be32_to_cpu(str->di_flags);
        di->di_payload_format = be32_to_cpu(str->di_payload_format);
@@ -205,6 +208,7 @@ void gfs2_dinode_out(struct gfs2_dinode *di, char *buf)
 
        str->di_goal_meta = cpu_to_be64(di->di_goal_meta);
        str->di_goal_data = cpu_to_be64(di->di_goal_data);
+       str->di_generation = cpu_to_be64(di->di_generation);
 
        str->di_flags = cpu_to_be32(di->di_flags);
        str->di_payload_format = cpu_to_be32(di->di_payload_format);
index 2c4ec5cf21ffebac2d30a4f36ec295d58645d4bc..031270ad55e2208768cf27cff5e5f40e924bccf7 100644 (file)
@@ -33,6 +33,7 @@
 #include "rgrp.h"
 #include "ops_file.h"
 #include "util.h"
+#include "glops.h"
 
 /**
  * gfs2_get_block - Fills in a buffer head with details about a block
@@ -659,6 +660,115 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
        return ret;
 }
 
+/**
+ * stuck_releasepage - We're stuck in gfs2_releasepage().  Print stuff out.
+ * @bh: the buffer we're stuck on
+ *
+ */
+
+static void stuck_releasepage(struct buffer_head *bh)
+{
+       struct inode *inode = bh->b_page->mapping->host;
+       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+       struct gfs2_bufdata *bd = bh->b_private;
+       struct gfs2_glock *gl;
+
+       fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
+       fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
+               (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
+       fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
+       fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
+
+       if (!bd)
+               return;
+
+       gl = bd->bd_gl;
+
+       fs_warn(sdp, "gl = (%u, %llu)\n", 
+               gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
+
+       fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
+               (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
+               (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
+
+       if (gl->gl_ops == &gfs2_inode_glops) {
+               struct gfs2_inode *ip = gl->gl_object;
+               unsigned int x;
+
+               if (!ip)
+                       return;
+
+               fs_warn(sdp, "ip = %llu %llu\n",
+                       (unsigned long long)ip->i_num.no_formal_ino,
+                       (unsigned long long)ip->i_num.no_addr);
+
+               for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
+                       fs_warn(sdp, "ip->i_cache[%u] = %s\n",
+                               x, (ip->i_cache[x]) ? "!NULL" : "NULL");
+       }
+}
+
+/**
+ * gfs2_aspace_releasepage - free the metadata associated with a page
+ * @page: the page that's being released
+ * @gfp_mask: passed from Linux VFS, ignored by us
+ *
+ * Call try_to_free_buffers() if the buffers in this page can be
+ * released.
+ *
+ * Returns: 0
+ */
+
+int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
+{
+       struct inode *aspace = page->mapping->host;
+       struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
+       struct buffer_head *bh, *head;
+       struct gfs2_bufdata *bd;
+       unsigned long t;
+
+       if (!page_has_buffers(page))
+               goto out;
+
+       head = bh = page_buffers(page);
+       do {
+               t = jiffies;
+
+               while (atomic_read(&bh->b_count)) {
+                       if (atomic_read(&aspace->i_writecount)) {
+                               if (time_after_eq(jiffies, t +
+                                   gfs2_tune_get(sdp, gt_stall_secs) * HZ)) {
+                                       stuck_releasepage(bh);
+                                       t = jiffies;
+                               }
+
+                               yield();
+                               continue;
+                       }
+
+                       return 0;
+               }
+
+               gfs2_assert_warn(sdp, !buffer_pinned(bh));
+
+               bd = bh->b_private;
+               if (bd) {
+                       gfs2_assert_warn(sdp, bd->bd_bh == bh);
+                       gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
+                       gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list));
+                       gfs2_assert_warn(sdp, !bd->bd_ail);
+                       kmem_cache_free(gfs2_bufdata_cachep, bd);
+                       bh->b_private = NULL;
+               }
+
+               bh = bh->b_this_page;
+       }
+       while (bh != head);
+
+ out:
+       return try_to_free_buffers(page);
+}
+
 const struct address_space_operations gfs2_file_aops = {
        .writepage = gfs2_writepage,
        .readpage = gfs2_readpage,
@@ -668,6 +778,7 @@ const struct address_space_operations gfs2_file_aops = {
        .commit_write = gfs2_commit_write,
        .bmap = gfs2_bmap,
        .invalidatepage = gfs2_invalidatepage,
+       .releasepage = gfs2_releasepage,
        .direct_IO = gfs2_direct_IO,
 };
 
index a7ef3bf36f3ebcfc327719d9fa844a7e0fe68c3e..dfc3dda6de11118cc67ba4c8d4f8b1bd61780d31 100644 (file)
@@ -13,5 +13,6 @@
 extern const struct address_space_operations gfs2_file_aops;
 extern int gfs2_get_block(struct inode *inode, sector_t lblock,
                          struct buffer_head *bh_result, int create);
+extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
 
 #endif /* __OPS_ADDRESS_DOT_H__ */
index c8e2c98700a7155a93743e626ba3e8c2c7960192..26f1d3249b0fce0803a77a67337d27f1128d8dd2 100644 (file)
@@ -333,7 +333,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length,
        int error;
 
        error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
-                                inum->no_formal_ino, type);
+                                inum->no_addr, type);
        if (error)
                return 1;
 
index 14c1f88bfb5d3e025e52ae8b27b2906d5c087fdc..65eea0b88bf7d858b54fef6095f12cdb5073e830 100644 (file)
@@ -1205,7 +1205,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart,
  * Returns: the allocated block
  */
 
-uint64_t gfs2_alloc_data(struct gfs2_inode *ip)
+u64 gfs2_alloc_data(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = &ip->i_alloc;
@@ -1249,7 +1249,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip)
  * Returns: the allocated block
  */
 
-uint64_t gfs2_alloc_meta(struct gfs2_inode *ip)
+u64 gfs2_alloc_meta(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = &ip->i_alloc;
@@ -1294,13 +1294,13 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip)
  * Returns: the block allocated
  */
 
-uint64_t gfs2_alloc_di(struct gfs2_inode *dip)
+u64 gfs2_alloc_di(struct gfs2_inode *dip, 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;
-       uint32_t blk;
-       uint64_t block;
+       u32 blk;
+       u64 block;
 
        blk = rgblk_search(rgd, rgd->rd_last_alloc_meta,
                           GFS2_BLKST_FREE, GFS2_BLKST_DINODE);
@@ -1312,7 +1312,7 @@ uint64_t gfs2_alloc_di(struct gfs2_inode *dip)
        gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
        rgd->rd_rg.rg_free--;
        rgd->rd_rg.rg_dinodes++;
-
+       *generation = rgd->rd_rg.rg_igeneration++;
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
        gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
 
index 9c42d2252ddd2fcb780f3438962b89f5e91745ec..14600944d1843a62a64a002d07d4f2227882ff8f 100644 (file)
@@ -37,9 +37,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip);
 
 unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block);
 
-uint64_t gfs2_alloc_data(struct gfs2_inode *ip);
-uint64_t gfs2_alloc_meta(struct gfs2_inode *ip);
-uint64_t gfs2_alloc_di(struct gfs2_inode *ip);
+u64 gfs2_alloc_data(struct gfs2_inode *ip);
+u64 gfs2_alloc_meta(struct gfs2_inode *ip);
+u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
 
 void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen);
 void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen);
index 1181da8319394e447496a999f2251965d7372c25..3ebd8743ce8c40deb3dc3bb1d462b4368f5f5eb1 100644 (file)
@@ -170,8 +170,10 @@ struct gfs2_rgrp {
        __be32 rg_flags;
        __be32 rg_free;
        __be32 rg_dinodes;
+       __be32 __pad;
+       __be64 rg_igeneration;
 
-       __u8 rg_reserved[92]; /* Several fields from gfs1 now reserved */
+       __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */
 };
 
 /*
@@ -248,7 +250,7 @@ struct gfs2_dinode {
         */
        __be64 di_goal_meta;    /* rgrp to alloc from next */
        __be64 di_goal_data;    /* data block goal */
-       __u32 __pad[2];
+       __be64 di_generation;   /* generation number for NFS */
 
        __be32 di_flags;        /* GFS2_DIF_... */
        __be32 di_payload_format;  /* GFS2_FORMAT_... */