diff options
-rw-r--r-- | fs/gfs2/dir.c | 40 | ||||
-rw-r--r-- | include/uapi/linux/gfs2_ondisk.h | 11 |
2 files changed, 47 insertions, 4 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index b2e5ebfb4bb1..fa32655449c8 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -834,6 +834,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, | |||
834 | struct gfs2_leaf *leaf; | 834 | struct gfs2_leaf *leaf; |
835 | struct gfs2_dirent *dent; | 835 | struct gfs2_dirent *dent; |
836 | struct qstr name = { .name = "" }; | 836 | struct qstr name = { .name = "" }; |
837 | struct timespec tv = CURRENT_TIME; | ||
837 | 838 | ||
838 | error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); | 839 | error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); |
839 | if (error) | 840 | if (error) |
@@ -850,7 +851,11 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, | |||
850 | leaf->lf_entries = 0; | 851 | leaf->lf_entries = 0; |
851 | leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); | 852 | leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); |
852 | leaf->lf_next = 0; | 853 | 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)); | ||
854 | dent = (struct gfs2_dirent *)(leaf+1); | 859 | dent = (struct gfs2_dirent *)(leaf+1); |
855 | gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); | 860 | gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); |
856 | *pbh = bh; | 861 | *pbh = bh; |
@@ -1612,11 +1617,31 @@ out: | |||
1612 | return ret; | 1617 | return ret; |
1613 | } | 1618 | } |
1614 | 1619 | ||
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 | |||
1615 | static int dir_new_leaf(struct inode *inode, const struct qstr *name) | 1639 | static int dir_new_leaf(struct inode *inode, const struct qstr *name) |
1616 | { | 1640 | { |
1617 | struct buffer_head *bh, *obh; | 1641 | struct buffer_head *bh, *obh; |
1618 | struct gfs2_inode *ip = GFS2_I(inode); | 1642 | struct gfs2_inode *ip = GFS2_I(inode); |
1619 | struct gfs2_leaf *leaf, *oleaf; | 1643 | struct gfs2_leaf *leaf, *oleaf; |
1644 | u32 dist = 1; | ||
1620 | int error; | 1645 | int error; |
1621 | u32 index; | 1646 | u32 index; |
1622 | u64 bn; | 1647 | u64 bn; |
@@ -1626,6 +1651,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) | |||
1626 | if (error) | 1651 | if (error) |
1627 | return error; | 1652 | return error; |
1628 | do { | 1653 | do { |
1654 | dist++; | ||
1629 | oleaf = (struct gfs2_leaf *)obh->b_data; | 1655 | oleaf = (struct gfs2_leaf *)obh->b_data; |
1630 | bn = be64_to_cpu(oleaf->lf_next); | 1656 | bn = be64_to_cpu(oleaf->lf_next); |
1631 | if (!bn) | 1657 | if (!bn) |
@@ -1643,6 +1669,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) | |||
1643 | brelse(obh); | 1669 | brelse(obh); |
1644 | return -ENOSPC; | 1670 | return -ENOSPC; |
1645 | } | 1671 | } |
1672 | leaf->lf_dist = cpu_to_be32(dist); | ||
1646 | oleaf->lf_next = cpu_to_be64(bh->b_blocknr); | 1673 | oleaf->lf_next = cpu_to_be64(bh->b_blocknr); |
1647 | brelse(bh); | 1674 | brelse(bh); |
1648 | brelse(obh); | 1675 | brelse(obh); |
@@ -1679,6 +1706,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, | |||
1679 | struct gfs2_inode *ip = GFS2_I(inode); | 1706 | struct gfs2_inode *ip = GFS2_I(inode); |
1680 | struct buffer_head *bh = da->bh; | 1707 | struct buffer_head *bh = da->bh; |
1681 | struct gfs2_dirent *dent = da->dent; | 1708 | struct gfs2_dirent *dent = da->dent; |
1709 | struct timespec tv; | ||
1682 | struct gfs2_leaf *leaf; | 1710 | struct gfs2_leaf *leaf; |
1683 | int error; | 1711 | int error; |
1684 | 1712 | ||
@@ -1693,15 +1721,18 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, | |||
1693 | dent = gfs2_init_dirent(inode, dent, name, bh); | 1721 | dent = gfs2_init_dirent(inode, dent, name, bh); |
1694 | gfs2_inum_out(nip, dent); | 1722 | gfs2_inum_out(nip, dent); |
1695 | dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); | 1723 | dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); |
1724 | tv = CURRENT_TIME; | ||
1696 | if (ip->i_diskflags & GFS2_DIF_EXHASH) { | 1725 | if (ip->i_diskflags & GFS2_DIF_EXHASH) { |
1697 | leaf = (struct gfs2_leaf *)bh->b_data; | 1726 | leaf = (struct gfs2_leaf *)bh->b_data; |
1698 | be16_add_cpu(&leaf->lf_entries, 1); | 1727 | 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); | ||
1699 | } | 1730 | } |
1700 | da->dent = NULL; | 1731 | da->dent = NULL; |
1701 | da->bh = NULL; | 1732 | da->bh = NULL; |
1702 | brelse(bh); | 1733 | brelse(bh); |
1703 | ip->i_entries++; | 1734 | 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; |
1705 | if (S_ISDIR(nip->i_inode.i_mode)) | 1736 | if (S_ISDIR(nip->i_inode.i_mode)) |
1706 | inc_nlink(&ip->i_inode); | 1737 | inc_nlink(&ip->i_inode); |
1707 | mark_inode_dirty(inode); | 1738 | mark_inode_dirty(inode); |
@@ -1752,6 +1783,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) | |||
1752 | const struct qstr *name = &dentry->d_name; | 1783 | const struct qstr *name = &dentry->d_name; |
1753 | struct gfs2_dirent *dent, *prev = NULL; | 1784 | struct gfs2_dirent *dent, *prev = NULL; |
1754 | struct buffer_head *bh; | 1785 | struct buffer_head *bh; |
1786 | struct timespec tv = CURRENT_TIME; | ||
1755 | 1787 | ||
1756 | /* Returns _either_ the entry (if its first in block) or the | 1788 | /* Returns _either_ the entry (if its first in block) or the |
1757 | previous entry otherwise */ | 1789 | previous entry otherwise */ |
@@ -1777,13 +1809,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) | |||
1777 | if (!entries) | 1809 | if (!entries) |
1778 | gfs2_consist_inode(dip); | 1810 | gfs2_consist_inode(dip); |
1779 | leaf->lf_entries = cpu_to_be16(--entries); | 1811 | 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); | ||
1780 | } | 1814 | } |
1781 | brelse(bh); | 1815 | brelse(bh); |
1782 | 1816 | ||
1783 | if (!dip->i_entries) | 1817 | if (!dip->i_entries) |
1784 | gfs2_consist_inode(dip); | 1818 | gfs2_consist_inode(dip); |
1785 | dip->i_entries--; | 1819 | 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; |
1787 | if (S_ISDIR(dentry->d_inode->i_mode)) | 1821 | if (S_ISDIR(dentry->d_inode->i_mode)) |
1788 | drop_nlink(&dip->i_inode); | 1822 | drop_nlink(&dip->i_inode); |
1789 | mark_inode_dirty(&dip->i_inode); | 1823 | mark_inode_dirty(&dip->i_inode); |
diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index b2de1f9a88d6..0f24c07aed51 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h | |||
@@ -319,7 +319,16 @@ struct gfs2_leaf { | |||
319 | __be32 lf_dirent_format; /* Format of the dirents */ | 319 | __be32 lf_dirent_format; /* Format of the dirents */ |
320 | __be64 lf_next; /* Next leaf, if overflow */ | 320 | __be64 lf_next; /* Next leaf, if overflow */ |
321 | 321 | ||
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 | }; | ||
323 | }; | 332 | }; |
324 | 333 | ||
325 | /* | 334 | /* |