diff options
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 78 |
1 files changed, 69 insertions, 9 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 34f7bcdea1e9..5f6dc32946cd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -77,6 +77,49 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) | |||
77 | return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); | 77 | return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); |
78 | } | 78 | } |
79 | 79 | ||
80 | struct gfs2_skip_data { | ||
81 | u64 no_addr; | ||
82 | int skipped; | ||
83 | }; | ||
84 | |||
85 | static int iget_skip_test(struct inode *inode, void *opaque) | ||
86 | { | ||
87 | struct gfs2_inode *ip = GFS2_I(inode); | ||
88 | struct gfs2_skip_data *data = opaque; | ||
89 | |||
90 | if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){ | ||
91 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ | ||
92 | data->skipped = 1; | ||
93 | return 0; | ||
94 | } | ||
95 | return 1; | ||
96 | } | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int iget_skip_set(struct inode *inode, void *opaque) | ||
101 | { | ||
102 | struct gfs2_inode *ip = GFS2_I(inode); | ||
103 | struct gfs2_skip_data *data = opaque; | ||
104 | |||
105 | if (data->skipped) | ||
106 | return 1; | ||
107 | inode->i_ino = (unsigned long)(data->no_addr); | ||
108 | ip->i_no_addr = data->no_addr; | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static struct inode *gfs2_iget_skip(struct super_block *sb, | ||
113 | u64 no_addr) | ||
114 | { | ||
115 | struct gfs2_skip_data data; | ||
116 | unsigned long hash = (unsigned long)no_addr; | ||
117 | |||
118 | data.no_addr = no_addr; | ||
119 | data.skipped = 0; | ||
120 | return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data); | ||
121 | } | ||
122 | |||
80 | /** | 123 | /** |
81 | * GFS2 lookup code fills in vfs inode contents based on info obtained | 124 | * GFS2 lookup code fills in vfs inode contents based on info obtained |
82 | * from directory entry inside gfs2_inode_lookup(). This has caused issues | 125 | * from directory entry inside gfs2_inode_lookup(). This has caused issues |
@@ -112,6 +155,7 @@ void gfs2_set_iop(struct inode *inode) | |||
112 | * @sb: The super block | 155 | * @sb: The super block |
113 | * @no_addr: The inode number | 156 | * @no_addr: The inode number |
114 | * @type: The type of the inode | 157 | * @type: The type of the inode |
158 | * @skip_freeing: set this not return an inode if it is currently being freed. | ||
115 | * | 159 | * |
116 | * Returns: A VFS inode, or an error | 160 | * Returns: A VFS inode, or an error |
117 | */ | 161 | */ |
@@ -119,13 +163,19 @@ void gfs2_set_iop(struct inode *inode) | |||
119 | struct inode *gfs2_inode_lookup(struct super_block *sb, | 163 | struct inode *gfs2_inode_lookup(struct super_block *sb, |
120 | unsigned int type, | 164 | unsigned int type, |
121 | u64 no_addr, | 165 | u64 no_addr, |
122 | u64 no_formal_ino) | 166 | u64 no_formal_ino, int skip_freeing) |
123 | { | 167 | { |
124 | struct inode *inode = gfs2_iget(sb, no_addr); | 168 | struct inode *inode; |
125 | struct gfs2_inode *ip = GFS2_I(inode); | 169 | struct gfs2_inode *ip; |
126 | struct gfs2_glock *io_gl; | 170 | struct gfs2_glock *io_gl; |
127 | int error; | 171 | int error; |
128 | 172 | ||
173 | if (skip_freeing) | ||
174 | inode = gfs2_iget_skip(sb, no_addr); | ||
175 | else | ||
176 | inode = gfs2_iget(sb, no_addr); | ||
177 | ip = GFS2_I(inode); | ||
178 | |||
129 | if (!inode) | 179 | if (!inode) |
130 | return ERR_PTR(-ENOBUFS); | 180 | return ERR_PTR(-ENOBUFS); |
131 | 181 | ||
@@ -244,6 +294,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) | |||
244 | return 0; | 294 | return 0; |
245 | } | 295 | } |
246 | 296 | ||
297 | static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh) | ||
298 | { | ||
299 | ip->i_cache[0] = bh; | ||
300 | } | ||
301 | |||
247 | /** | 302 | /** |
248 | * gfs2_inode_refresh - Refresh the incore copy of the dinode | 303 | * gfs2_inode_refresh - Refresh the incore copy of the dinode |
249 | * @ip: The GFS2 inode | 304 | * @ip: The GFS2 inode |
@@ -688,7 +743,7 @@ out: | |||
688 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 743 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
689 | const struct gfs2_inum_host *inum, unsigned int mode, | 744 | const struct gfs2_inum_host *inum, unsigned int mode, |
690 | unsigned int uid, unsigned int gid, | 745 | unsigned int uid, unsigned int gid, |
691 | const u64 *generation, dev_t dev) | 746 | const u64 *generation, dev_t dev, struct buffer_head **bhp) |
692 | { | 747 | { |
693 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 748 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
694 | struct gfs2_dinode *di; | 749 | struct gfs2_dinode *di; |
@@ -743,13 +798,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
743 | di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); | 798 | di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); |
744 | di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); | 799 | di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); |
745 | memset(&di->di_reserved, 0, sizeof(di->di_reserved)); | 800 | memset(&di->di_reserved, 0, sizeof(di->di_reserved)); |
801 | |||
802 | set_buffer_uptodate(dibh); | ||
746 | 803 | ||
747 | brelse(dibh); | 804 | *bhp = dibh; |
748 | } | 805 | } |
749 | 806 | ||
750 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 807 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
751 | unsigned int mode, const struct gfs2_inum_host *inum, | 808 | unsigned int mode, const struct gfs2_inum_host *inum, |
752 | const u64 *generation, dev_t dev) | 809 | const u64 *generation, dev_t dev, struct buffer_head **bhp) |
753 | { | 810 | { |
754 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 811 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
755 | unsigned int uid, gid; | 812 | unsigned int uid, gid; |
@@ -770,7 +827,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
770 | if (error) | 827 | if (error) |
771 | goto out_quota; | 828 | goto out_quota; |
772 | 829 | ||
773 | init_dinode(dip, gl, inum, mode, uid, gid, generation, dev); | 830 | init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); |
774 | gfs2_quota_change(dip, +1, uid, gid); | 831 | gfs2_quota_change(dip, +1, uid, gid); |
775 | gfs2_trans_end(sdp); | 832 | gfs2_trans_end(sdp); |
776 | 833 | ||
@@ -909,6 +966,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
909 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; | 966 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; |
910 | int error; | 967 | int error; |
911 | u64 generation; | 968 | u64 generation; |
969 | struct buffer_head *bh=NULL; | ||
912 | 970 | ||
913 | if (!name->len || name->len > GFS2_FNAMESIZE) | 971 | if (!name->len || name->len > GFS2_FNAMESIZE) |
914 | return ERR_PTR(-ENAMETOOLONG); | 972 | return ERR_PTR(-ENAMETOOLONG); |
@@ -935,16 +993,18 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
935 | if (error) | 993 | if (error) |
936 | goto fail_gunlock; | 994 | goto fail_gunlock; |
937 | 995 | ||
938 | error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev); | 996 | error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); |
939 | if (error) | 997 | if (error) |
940 | goto fail_gunlock2; | 998 | goto fail_gunlock2; |
941 | 999 | ||
942 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), | 1000 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), |
943 | inum.no_addr, | 1001 | inum.no_addr, |
944 | inum.no_formal_ino); | 1002 | inum.no_formal_ino, 0); |
945 | if (IS_ERR(inode)) | 1003 | if (IS_ERR(inode)) |
946 | goto fail_gunlock2; | 1004 | goto fail_gunlock2; |
947 | 1005 | ||
1006 | gfs2_inode_bh(GFS2_I(inode), bh); | ||
1007 | |||
948 | error = gfs2_inode_refresh(GFS2_I(inode)); | 1008 | error = gfs2_inode_refresh(GFS2_I(inode)); |
949 | if (error) | 1009 | if (error) |
950 | goto fail_gunlock2; | 1010 | goto fail_gunlock2; |