History

GFS2: Add hints to directory leaf blocks

This patch adds four new fields to directory leaf blocks. The intent is not to use them in the kernel itself, although perhaps we may be able to use them as hints at some later date, but instead to provide more information for debug/fsck use. One new field adds a pointer to the inode to which the leaf belongs. This can be useful if the pointer to the leaf block has become corrupt, as it will allow us to know which inode this block should be associated with. This field is set when the leaf is created and never changed over its lifetime. The second field is a "distance from the hash table" field. The meaning is as follows: 0 = An old leaf in which this value has not been set 1 = This leaf is pointed to directly from the hash table 2+ = This leaf is part of a chain, pointed to by another leaf block, the value gives the position in the chain. The third and fourth fields combine to give a time stamp of the most recent directory insertion or deletion from this leaf block. The time stamp is not updated when a new leaf block is chained from the current one. The code is currently written such that the timestamp on the dir inode will match that of the leaf block for the most recent insertion/deletion. For backwards compatibility, any of these new fields which is zero should be considered to be "unknown".

Steven Whitehouse committed 12 years ago

Commit 01bcb0d1 parent 22b5a6c2 files · +47 −4Browse files

Unified · Split

2 files
  1. fs/gfs2/dir.c +37 −3
  2. include/uapi/linux/gfs2_ondisk.h +10 −1
fs/gfs2/dir.c+37−3
@@ -834,6 +834,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, · 833 unmodified lines
834834 struct gfs2_leaf *leaf;
835835 struct gfs2_dirent *dent;
836836 struct qstr name = { .name = "" };
837+ struct timespec tv = CURRENT_TIME;
837838
838839 error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
839840 if (error)
@@ -850,7 +851,11 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, · 10 unmodified lines
850851 leaf->lf_entries = 0;
851852 leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
852853 leaf->lf_next = 0;
853− memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));
854+ leaf->lf_inode = cpu_to_be64(ip->i_no_addr);
855+ leaf->lf_dist = cpu_to_be32(1);
856+ leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
857+ leaf->lf_sec = cpu_to_be64(tv.tv_sec);
858+ memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2));
854859 dent = (struct gfs2_dirent *)(leaf+1);
855860 gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
856861 *pbh = bh;
@@ -1612,11 +1617,31 @@ out: · 755 unmodified lines
16121617 return ret;
16131618 }
16141619
1620+/**
1621+ * dir_new_leaf - Add a new leaf onto hash chain
1622+ * @inode: The directory
1623+ * @name: The name we are adding
1624+ *
1625+ * This adds a new dir leaf onto an existing leaf when there is not
1626+ * enough space to add a new dir entry. This is a last resort after
1627+ * we've expanded the hash table to max size and also split existing
1628+ * leaf blocks, so it will only occur for very large directories.
1629+ *
1630+ * The dist parameter is set to 1 for leaf blocks directly attached
1631+ * to the hash table, 2 for one layer of indirection, 3 for two layers
1632+ * etc. We are thus able to tell the difference between an old leaf
1633+ * with dist set to zero (i.e. "don't know") and a new one where we
1634+ * set this information for debug/fsck purposes.
1635+ *
1636+ * Returns: 0 on success, or -ve on error
1637+ */
1638+
16151639 static int dir_new_leaf(struct inode *inode, const struct qstr *name)
16161640 {
16171641 struct buffer_head *bh, *obh;
16181642 struct gfs2_inode *ip = GFS2_I(inode);
16191643 struct gfs2_leaf *leaf, *oleaf;
1644+ u32 dist = 1;
16201645 int error;
16211646 u32 index;
16221647 u64 bn;
@@ -1626,6 +1651,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) · 3 unmodified lines
16261651 if (error)
16271652 return error;
16281653 do {
1654+ dist++;
16291655 oleaf = (struct gfs2_leaf *)obh->b_data;
16301656 bn = be64_to_cpu(oleaf->lf_next);
16311657 if (!bn)
@@ -1643,6 +1669,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) · 11 unmodified lines
16431669 brelse(obh);
16441670 return -ENOSPC;
16451671 }
1672+ leaf->lf_dist = cpu_to_be32(dist);
16461673 oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
16471674 brelse(bh);
16481675 brelse(obh);
@@ -1679,6 +1706,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, · 30 unmodified lines
16791706 struct gfs2_inode *ip = GFS2_I(inode);
16801707 struct buffer_head *bh = da->bh;
16811708 struct gfs2_dirent *dent = da->dent;
1709+ struct timespec tv;
16821710 struct gfs2_leaf *leaf;
16831711 int error;
16841712
@@ -1693,15 +1721,18 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, · 8 unmodified lines
16931721 dent = gfs2_init_dirent(inode, dent, name, bh);
16941722 gfs2_inum_out(nip, dent);
16951723 dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode));
1724+ tv = CURRENT_TIME;
16961725 if (ip->i_diskflags & GFS2_DIF_EXHASH) {
16971726 leaf = (struct gfs2_leaf *)bh->b_data;
16981727 be16_add_cpu(&leaf->lf_entries, 1);
1728+ leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
1729+ leaf->lf_sec = cpu_to_be64(tv.tv_sec);
16991730 }
17001731 da->dent = NULL;
17011732 da->bh = NULL;
17021733 brelse(bh);
17031734 ip->i_entries++;
1704− ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
1735+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = tv;
17051736 if (S_ISDIR(nip->i_inode.i_mode))
17061737 inc_nlink(&ip->i_inode);
17071738 mark_inode_dirty(inode);
@@ -1752,6 +1783,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) · 44 unmodified lines
17521783 const struct qstr *name = &dentry->d_name;
17531784 struct gfs2_dirent *dent, *prev = NULL;
17541785 struct buffer_head *bh;
1786+ struct timespec tv = CURRENT_TIME;
17551787
17561788 /* Returns _either_ the entry (if its first in block) or the
17571789 previous entry otherwise */
@@ -1777,13 +1809,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) · 19 unmodified lines
17771809 if (!entries)
17781810 gfs2_consist_inode(dip);
17791811 leaf->lf_entries = cpu_to_be16(--entries);
1812+ leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
1813+ leaf->lf_sec = cpu_to_be64(tv.tv_sec);
17801814 }
17811815 brelse(bh);
17821816
17831817 if (!dip->i_entries)
17841818 gfs2_consist_inode(dip);
17851819 dip->i_entries--;
1786− dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
1820+ dip->i_inode.i_mtime = dip->i_inode.i_ctime = tv;
17871821 if (S_ISDIR(dentry->d_inode->i_mode))
17881822 drop_nlink(&dip->i_inode);
17891823 mark_inode_dirty(&dip->i_inode);
include/uapi/linux/gfs2_ondisk.h+10−1
@@ -319,7 +319,16 @@ struct gfs2_leaf { · 318 unmodified lines
319319 __be32 lf_dirent_format; /* Format of the dirents */
320320 __be64 lf_next; /* Next leaf, if overflow */
321321
322− __u8 lf_reserved[64];
322+ union {
323+ __u8 lf_reserved[64];
324+ struct {
325+ __be64 lf_inode; /* Dir inode number */
326+ __be32 lf_dist; /* Dist from inode on chain */
327+ __be32 lf_nsec; /* Last ins/del usecs */
328+ __be64 lf_sec; /* Last ins/del in secs */
329+ __u8 lf_reserved2[40];
330+ };
331+ };
323332 };
324333
325334 /*