aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-04-28 10:46:21 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-04-28 10:46:21 -0400
commit363275216c1a1b0b82c8419310c194b8c26b9c27 (patch)
tree476bb04ff32ac1724afa192f4950f4a39a0237f2 /fs
parentd26046bb0aff707aac38a9bf3dd56fa39b28a399 (diff)
[GFS2] Reordering in deallocation to avoid recursive locking
Despite my earlier careful search, there was a recursive lock left in the deallocation code. This removes it. It also should speed up deallocation be reducing the number of locking operations which take place by using two "try lock" operations on the two locks involved in inode deallocation which allows us to grab the locks out of order (compared with NFS which grabs the inode lock first and the iopen lock later). It is ok for us to fail while doing this since if it does fail it means that someone else is still using the inode and thus it wouldn't be possible to deallocate anyway. This fixes the bug reported to me by Rob Kenna. Cc: Rob Kenna <rkenna@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/glock.c6
-rw-r--r--fs/gfs2/inode.c95
-rw-r--r--fs/gfs2/inode.h2
3 files changed, 49 insertions, 54 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 17d474fab5ab..f82ecc0cc8fb 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1814,7 +1814,7 @@ void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum)
1814 if (atomic_read(&ip->i_count)) 1814 if (atomic_read(&ip->i_count))
1815 goto out_unlock; 1815 goto out_unlock;
1816 1816
1817 gfs2_inode_destroy(ip); 1817 gfs2_inode_destroy(ip, 1);
1818 1818
1819 out_unlock: 1819 out_unlock:
1820 gfs2_glmutex_unlock(gl); 1820 gfs2_glmutex_unlock(gl);
@@ -1940,7 +1940,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
1940 if (gl->gl_ops == &gfs2_inode_glops) { 1940 if (gl->gl_ops == &gfs2_inode_glops) {
1941 struct gfs2_inode *ip = gl->gl_object; 1941 struct gfs2_inode *ip = gl->gl_object;
1942 if (ip && !atomic_read(&ip->i_count)) 1942 if (ip && !atomic_read(&ip->i_count))
1943 gfs2_inode_destroy(ip); 1943 gfs2_inode_destroy(ip, 1);
1944 } 1944 }
1945 if (queue_empty(gl, &gl->gl_holders) && 1945 if (queue_empty(gl, &gl->gl_holders) &&
1946 gl->gl_state != LM_ST_UNLOCKED && 1946 gl->gl_state != LM_ST_UNLOCKED &&
@@ -2083,7 +2083,7 @@ static void clear_glock(struct gfs2_glock *gl)
2083 if (gl->gl_ops == &gfs2_inode_glops) { 2083 if (gl->gl_ops == &gfs2_inode_glops) {
2084 struct gfs2_inode *ip = gl->gl_object; 2084 struct gfs2_inode *ip = gl->gl_object;
2085 if (ip && !atomic_read(&ip->i_count)) 2085 if (ip && !atomic_read(&ip->i_count))
2086 gfs2_inode_destroy(ip); 2086 gfs2_inode_destroy(ip, 1);
2087 } 2087 }
2088 if (queue_empty(gl, &gl->gl_holders) && 2088 if (queue_empty(gl, &gl->gl_holders) &&
2089 gl->gl_state != LM_ST_UNLOCKED) 2089 gl->gl_state != LM_ST_UNLOCKED)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index fb5a4d06e926..9084d6037a0c 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -287,7 +287,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
287 287
288static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, 288static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum,
289 struct gfs2_glock *io_gl, unsigned int io_state, 289 struct gfs2_glock *io_gl, unsigned int io_state,
290 struct gfs2_inode **ipp) 290 struct gfs2_inode **ipp, int need_lock)
291{ 291{
292 struct gfs2_sbd *sdp = i_gl->gl_sbd; 292 struct gfs2_sbd *sdp = i_gl->gl_sbd;
293 struct gfs2_inode *ip; 293 struct gfs2_inode *ip;
@@ -312,11 +312,13 @@ static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum,
312 312
313 ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); 313 ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
314 314
315 error = gfs2_glock_nq_init(io_gl, 315 if (need_lock) {
316 io_state, GL_LOCAL_EXCL | GL_EXACT, 316 error = gfs2_glock_nq_init(io_gl,
317 &ip->i_iopen_gh); 317 io_state, GL_LOCAL_EXCL | GL_EXACT,
318 if (error) 318 &ip->i_iopen_gh);
319 goto fail; 319 if (error)
320 goto fail;
321 }
320 ip->i_iopen_gh.gh_owner = NULL; 322 ip->i_iopen_gh.gh_owner = NULL;
321 323
322 spin_lock(&io_gl->gl_spin); 324 spin_lock(&io_gl->gl_spin);
@@ -376,7 +378,7 @@ int gfs2_inode_get(struct gfs2_glock *i_gl, const struct gfs2_inum *inum,
376 error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, 378 error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops,
377 CREATE, &io_gl); 379 CREATE, &io_gl);
378 if (!error) { 380 if (!error) {
379 error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp); 381 error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp, 1);
380 gfs2_glock_put(io_gl); 382 gfs2_glock_put(io_gl);
381 } 383 }
382 384
@@ -398,21 +400,23 @@ void gfs2_inode_put(struct gfs2_inode *ip)
398 atomic_dec(&ip->i_count); 400 atomic_dec(&ip->i_count);
399} 401}
400 402
401void gfs2_inode_destroy(struct gfs2_inode *ip) 403void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock)
402{ 404{
403 struct gfs2_sbd *sdp = ip->i_sbd; 405 struct gfs2_sbd *sdp = ip->i_sbd;
404 struct gfs2_glock *io_gl = ip->i_iopen_gh.gh_gl;
405 struct gfs2_glock *i_gl = ip->i_gl; 406 struct gfs2_glock *i_gl = ip->i_gl;
406 407
407 gfs2_assert_warn(sdp, !atomic_read(&ip->i_count)); 408 gfs2_assert_warn(sdp, !atomic_read(&ip->i_count));
408 gfs2_assert(sdp, io_gl->gl_object == i_gl); 409 if (unlock) {
409 410 struct gfs2_glock *io_gl = ip->i_iopen_gh.gh_gl;
410 spin_lock(&io_gl->gl_spin); 411 gfs2_assert(sdp, io_gl->gl_object == i_gl);
411 io_gl->gl_object = NULL; 412
412 spin_unlock(&io_gl->gl_spin); 413 spin_lock(&io_gl->gl_spin);
413 gfs2_glock_put(i_gl); 414 io_gl->gl_object = NULL;
414 415 spin_unlock(&io_gl->gl_spin);
415 gfs2_glock_dq_uninit(&ip->i_iopen_gh); 416 gfs2_glock_put(i_gl);
417
418 gfs2_glock_dq_uninit(&ip->i_iopen_gh);
419 }
416 420
417 gfs2_meta_cache_flush(ip); 421 gfs2_meta_cache_flush(ip);
418 kmem_cache_free(gfs2_inode_cachep, ip); 422 kmem_cache_free(gfs2_inode_cachep, ip);
@@ -493,6 +497,13 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul)
493 * @inum: the inode number to deallocate 497 * @inum: the inode number to deallocate
494 * @io_gh: a holder for the iopen glock for this inode 498 * @io_gh: a holder for the iopen glock for this inode
495 * 499 *
500 * N.B. When we enter this we already hold the iopen glock and getting
501 * the glock for the inode means that we are grabbing the locks in the
502 * "wrong" order so we must only so a try lock operation and fail if we
503 * don't get the lock. Thats ok, since if we fail it means someone else
504 * is using the inode still and thus we shouldn't be deallocating it
505 * anyway.
506 *
496 * Returns: errno 507 * Returns: errno
497 */ 508 */
498 509
@@ -503,33 +514,21 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul,
503 struct gfs2_holder i_gh; 514 struct gfs2_holder i_gh;
504 int error; 515 int error;
505 516
506 error = gfs2_glock_nq_num(sdp, 517 error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr,
507 ul->ul_ut.ut_inum.no_addr, &gfs2_inode_glops, 518 &gfs2_inode_glops, LM_ST_EXCLUSIVE,
508 LM_ST_EXCLUSIVE, 0, &i_gh); 519 LM_FLAG_TRY_1CB, &i_gh);
509 if (error) 520 switch(error) {
510 return error;
511
512 /* We reacquire the iopen lock here to avoid a race with the NFS server
513 calling gfs2_read_inode() with the inode number of a inode we're in
514 the process of deallocating. And we can't keep our hold on the lock
515 from inode_dealloc_init() for deadlock reasons. */
516
517 gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY, io_gh);
518 error = gfs2_glock_nq(io_gh);
519 switch (error) {
520 case 0: 521 case 0:
521 break; 522 break;
522 case GLR_TRYFAILED: 523 case GLR_TRYFAILED:
523 error = 1; 524 return 1; /* or back off and relock in different order? */
524 default: 525 default:
525 goto out; 526 return error;
526 } 527 }
527 528
528 gfs2_assert_warn(sdp, !i_gh.gh_gl->gl_object); 529 gfs2_assert_warn(sdp, !i_gh.gh_gl->gl_object);
529 error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl, 530 error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl,
530 LM_ST_EXCLUSIVE, &ip); 531 LM_ST_EXCLUSIVE, &ip, 0);
531
532 gfs2_glock_dq(io_gh);
533 532
534 if (error) 533 if (error)
535 goto out; 534 goto out;
@@ -568,13 +567,13 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul,
568 if (error) 567 if (error)
569 goto out_iput; 568 goto out_iput;
570 569
571 out_iput: 570out_iput:
572 gfs2_glmutex_lock(i_gh.gh_gl); 571 gfs2_glmutex_lock(i_gh.gh_gl);
573 gfs2_inode_put(ip); 572 gfs2_inode_put(ip);
574 gfs2_inode_destroy(ip); 573 gfs2_inode_destroy(ip, 0);
575 gfs2_glmutex_unlock(i_gh.gh_gl); 574 gfs2_glmutex_unlock(i_gh.gh_gl);
576 575
577 out: 576out:
578 gfs2_glock_dq_uninit(&i_gh); 577 gfs2_glock_dq_uninit(&i_gh);
579 578
580 return error; 579 return error;
@@ -589,14 +588,13 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul,
589 588
590static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) 589static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul)
591{ 590{
592 struct gfs2_holder io_gh;
593 int error = 0; 591 int error = 0;
592 struct gfs2_holder iogh;
594 593
595 gfs2_try_toss_inode(sdp, &ul->ul_ut.ut_inum); 594 gfs2_try_toss_inode(sdp, &ul->ul_ut.ut_inum);
596 595 error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr,
597 error = gfs2_glock_nq_num(sdp, 596 &gfs2_iopen_glops, LM_ST_EXCLUSIVE,
598 ul->ul_ut.ut_inum.no_addr, &gfs2_iopen_glops, 597 LM_FLAG_TRY_1CB, &iogh);
599 LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB, &io_gh);
600 switch (error) { 598 switch (error) {
601 case 0: 599 case 0:
602 break; 600 break;
@@ -606,9 +604,8 @@ static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul)
606 return error; 604 return error;
607 } 605 }
608 606
609 gfs2_glock_dq(&io_gh); 607 error = inode_dealloc(sdp, ul, &iogh);
610 error = inode_dealloc(sdp, ul, &io_gh); 608 gfs2_glock_dq_uninit(&iogh);
611 gfs2_holder_uninit(&io_gh);
612 609
613 return error; 610 return error;
614} 611}
@@ -634,9 +631,7 @@ static int inode_dealloc_uninit(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul)
634 if (error) 631 if (error)
635 goto out; 632 goto out;
636 633
637 error = gfs2_trans_begin(sdp, 634 error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + RES_STATFS, 0);
638 RES_RG_BIT + RES_UNLINKED + RES_STATFS,
639 0);
640 if (error) 635 if (error)
641 goto out_gunlock; 636 goto out_gunlock;
642 637
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 0dd2a26626ec..13bc4eacac6b 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -39,7 +39,7 @@ int gfs2_inode_get(struct gfs2_glock *i_gl,
39 struct gfs2_inode **ipp); 39 struct gfs2_inode **ipp);
40void gfs2_inode_hold(struct gfs2_inode *ip); 40void gfs2_inode_hold(struct gfs2_inode *ip);
41void gfs2_inode_put(struct gfs2_inode *ip); 41void gfs2_inode_put(struct gfs2_inode *ip);
42void gfs2_inode_destroy(struct gfs2_inode *ip); 42void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock);
43 43
44int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); 44int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul);
45 45