summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/inode.c46
-rw-r--r--fs/gfs2/meta_io.c112
-rw-r--r--fs/gfs2/ondisk.c6
-rw-r--r--fs/gfs2/ops_address.c111
-rw-r--r--fs/gfs2/ops_address.h1
-rw-r--r--fs/gfs2/ops_file.c2
-rw-r--r--fs/gfs2/rgrp.c12
-rw-r--r--fs/gfs2/rgrp.h6
-rw-r--r--include/linux/gfs2_ondisk.h6
9 files changed, 153 insertions, 149 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index f4c48395208a..22ca3b5ddaea 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -38,15 +38,17 @@
#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:
@@ -85,18 +87,6 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode)
}
/**
- * 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;
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index ddcd4dc1081d..cad44fd70d67 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -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,
};
/**
diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c
index 09154ad7b270..39c7f0345fc6 100644
--- a/fs/gfs2/ondisk.c
+++ b/fs/gfs2/ondisk.c
@@ -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);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 2c4ec5cf21ff..031270ad55e2 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -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,
};
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
index a7ef3bf36f3e..dfc3dda6de11 100644
--- a/fs/gfs2/ops_address.h
+++ b/fs/gfs2/ops_address.h
@@ -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__ */
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index c8e2c98700a7..26f1d3249b0f 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -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;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 14c1f88bfb5d..65eea0b88bf7 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -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);
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index 9c42d2252ddd..14600944d184 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -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);
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index 1181da831939..3ebd8743ce8c 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -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_... */