aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2011-05-05 07:35:40 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2011-05-05 07:35:40 -0400
commitd192a8e5c6fec4fe8cdafebccc415db4074dee88 (patch)
tree7c66540003f6aea894578f6786599bd08dcb9b7f /fs
parent8f065d36508f283ee6cbeb05829f032d0b782a16 (diff)
GFS2: Double check link count under glock
To avoid any possible races relating to the link count, we need to recheck it under the inode's glock in all cases where it matters. Also to ensure we never get any nasty surprises, this patch also ensures that once the link count has hit zero it can never be elevated by rereading in data from disk. The only place we cannot provide a proper solution is in rename in the case where we are removing a target inode and we discover that the target inode has been already unlinked on another node. The race window is very small, and we return EAGAIN in this case to indicate what has happened. The proper solution would be to move the lookup parts of rename from the vfs into library calls which the fs could call directly, but that is potentially a very big job and this fix should cover most cases for now. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/inode.c35
-rw-r--r--fs/gfs2/ops_inode.c23
2 files changed, 50 insertions, 8 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 94c3a7db1116..5a02606b68c0 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -248,6 +248,32 @@ fail_iput:
248 goto fail; 248 goto fail;
249} 249}
250 250
251/**
252 * gfs2_set_nlink - Set the inode's link count based on on-disk info
253 * @inode: The inode in question
254 * @nlink: The link count
255 *
256 * If the link count has hit zero, it must never be raised, whatever the
257 * on-disk inode might say. When new struct inodes are created the link
258 * count is set to 1, so that we can safely use this test even when reading
259 * in on disk information for the first time.
260 */
261
262static void gfs2_set_nlink(struct inode *inode, u32 nlink)
263{
264 /*
265 * We will need to review setting the nlink count here in the
266 * light of the forthcoming ro bind mount work. This is a reminder
267 * to do that.
268 */
269 if ((inode->i_nlink != nlink) && (inode->i_nlink != 0)) {
270 if (nlink == 0)
271 clear_nlink(inode);
272 else
273 inode->i_nlink = nlink;
274 }
275}
276
251static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) 277static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
252{ 278{
253 const struct gfs2_dinode *str = buf; 279 const struct gfs2_dinode *str = buf;
@@ -269,12 +295,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
269 295
270 ip->i_inode.i_uid = be32_to_cpu(str->di_uid); 296 ip->i_inode.i_uid = be32_to_cpu(str->di_uid);
271 ip->i_inode.i_gid = be32_to_cpu(str->di_gid); 297 ip->i_inode.i_gid = be32_to_cpu(str->di_gid);
272 /* 298 gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink));
273 * We will need to review setting the nlink count here in the
274 * light of the forthcoming ro bind mount work. This is a reminder
275 * to do that.
276 */
277 ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);
278 i_size_write(&ip->i_inode, be64_to_cpu(str->di_size)); 299 i_size_write(&ip->i_inode, be64_to_cpu(str->di_size));
279 gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); 300 gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
280 atime.tv_sec = be64_to_cpu(str->di_atime); 301 atime.tv_sec = be64_to_cpu(str->di_atime);
@@ -484,7 +505,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
484 505
485 /* Don't create entries in an unlinked directory */ 506 /* Don't create entries in an unlinked directory */
486 if (!dip->i_inode.i_nlink) 507 if (!dip->i_inode.i_nlink)
487 return -EPERM; 508 return -ENOENT;
488 509
489 error = gfs2_dir_check(&dip->i_inode, name, NULL); 510 error = gfs2_dir_check(&dip->i_inode, name, NULL);
490 switch (error) { 511 switch (error) {
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 09e436a50723..1005f9eb456e 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -162,6 +162,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
162 if (error) 162 if (error)
163 goto out_child; 163 goto out_child;
164 164
165 error = -ENOENT;
166 if (inode->i_nlink == 0)
167 goto out_gunlock;
168
165 error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); 169 error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0);
166 if (error) 170 if (error)
167 goto out_gunlock; 171 goto out_gunlock;
@@ -335,6 +339,10 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
335 if (error) 339 if (error)
336 goto out_child; 340 goto out_child;
337 341
342 error = -ENOENT;
343 if (ip->i_inode.i_nlink == 0)
344 goto out_rgrp;
345
338 error = gfs2_glock_nq(ghs + 2); /* rgrp */ 346 error = gfs2_glock_nq(ghs + 2); /* rgrp */
339 if (error) 347 if (error)
340 goto out_rgrp; 348 goto out_rgrp;
@@ -589,6 +597,10 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
589 if (error) 597 if (error)
590 goto out_child; 598 goto out_child;
591 599
600 error = -ENOENT;
601 if (ip->i_inode.i_nlink == 0)
602 goto out_rgrp;
603
592 error = gfs2_glock_nq(ghs + 2); /* rgrp */ 604 error = gfs2_glock_nq(ghs + 2); /* rgrp */
593 if (error) 605 if (error)
594 goto out_rgrp; 606 goto out_rgrp;
@@ -792,6 +804,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
792 goto out_gunlock; 804 goto out_gunlock;
793 } 805 }
794 806
807 error = -ENOENT;
808 if (ip->i_inode.i_nlink == 0)
809 goto out_gunlock;
810
795 /* Check out the old directory */ 811 /* Check out the old directory */
796 812
797 error = gfs2_unlink_ok(odip, &odentry->d_name, ip); 813 error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
@@ -805,6 +821,11 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
805 if (error) 821 if (error)
806 goto out_gunlock; 822 goto out_gunlock;
807 823
824 if (nip->i_inode.i_nlink == 0) {
825 error = -EAGAIN;
826 goto out_gunlock;
827 }
828
808 if (S_ISDIR(nip->i_inode.i_mode)) { 829 if (S_ISDIR(nip->i_inode.i_mode)) {
809 if (nip->i_entries < 2) { 830 if (nip->i_entries < 2) {
810 if (gfs2_consist_inode(nip)) 831 if (gfs2_consist_inode(nip))
@@ -835,7 +856,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
835 856
836 if (odip != ndip) { 857 if (odip != ndip) {
837 if (!ndip->i_inode.i_nlink) { 858 if (!ndip->i_inode.i_nlink) {
838 error = -EINVAL; 859 error = -ENOENT;
839 goto out_gunlock; 860 goto out_gunlock;
840 } 861 }
841 if (ndip->i_entries == (u32)-1) { 862 if (ndip->i_entries == (u32)-1) {