diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-01-25 12:14:59 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-02-05 13:37:53 -0500 |
commit | d7c103d0bd29c94f78155a4538faf314e49d9713 (patch) | |
tree | 62c453ffe7d6d4637aa93dd43dbb0665175f644c /fs/gfs2/inode.c | |
parent | b790c3b7c38aae28c497bb363a6fe72f7c96568f (diff) |
[GFS2] Fix recursive locking attempt with NFS
In certain cases, its possible for NFS to call the lookup code while
holding the glock (when doing a readdirplus operation) so we need to
check for that and not try and lock the glock twice. This also fixes a
typo in a previous NFS related GFS2 patch.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f7c8d31ce41a..88fcfb4f5c4d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -395,8 +395,10 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) | |||
395 | * @is_root: If 1, ignore the caller's permissions | 395 | * @is_root: If 1, ignore the caller's permissions |
396 | * @i_gh: An uninitialized holder for the new inode glock | 396 | * @i_gh: An uninitialized holder for the new inode glock |
397 | * | 397 | * |
398 | * There will always be a vnode (Linux VFS inode) for the d_gh inode unless | 398 | * This can be called via the VFS filldir function when NFS is doing |
399 | * @is_root is true. | 399 | * a readdirplus and the inode which its intending to stat isn't |
400 | * already in cache. In this case we must not take the directory glock | ||
401 | * again, since the readdir call will have already taken that lock. | ||
400 | * | 402 | * |
401 | * Returns: errno | 403 | * Returns: errno |
402 | */ | 404 | */ |
@@ -409,8 +411,9 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | |||
409 | struct gfs2_holder d_gh; | 411 | struct gfs2_holder d_gh; |
410 | struct gfs2_inum_host inum; | 412 | struct gfs2_inum_host inum; |
411 | unsigned int type; | 413 | unsigned int type; |
412 | int error = 0; | 414 | int error; |
413 | struct inode *inode = NULL; | 415 | struct inode *inode = NULL; |
416 | int unlock = 0; | ||
414 | 417 | ||
415 | if (!name->len || name->len > GFS2_FNAMESIZE) | 418 | if (!name->len || name->len > GFS2_FNAMESIZE) |
416 | return ERR_PTR(-ENAMETOOLONG); | 419 | return ERR_PTR(-ENAMETOOLONG); |
@@ -422,9 +425,12 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | |||
422 | return dir; | 425 | return dir; |
423 | } | 426 | } |
424 | 427 | ||
425 | error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); | 428 | if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) { |
426 | if (error) | 429 | error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); |
427 | return ERR_PTR(error); | 430 | if (error) |
431 | return ERR_PTR(error); | ||
432 | unlock = 1; | ||
433 | } | ||
428 | 434 | ||
429 | if (!is_root) { | 435 | if (!is_root) { |
430 | error = permission(dir, MAY_EXEC, NULL); | 436 | error = permission(dir, MAY_EXEC, NULL); |
@@ -439,10 +445,11 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | |||
439 | inode = gfs2_inode_lookup(sb, &inum, type); | 445 | inode = gfs2_inode_lookup(sb, &inum, type); |
440 | 446 | ||
441 | out: | 447 | out: |
442 | gfs2_glock_dq_uninit(&d_gh); | 448 | if (unlock) |
449 | gfs2_glock_dq_uninit(&d_gh); | ||
443 | if (error == -ENOENT) | 450 | if (error == -ENOENT) |
444 | return NULL; | 451 | return NULL; |
445 | return inode; | 452 | return inode ? inode : ERR_PTR(error); |
446 | } | 453 | } |
447 | 454 | ||
448 | static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) | 455 | static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) |