diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-06-25 16:35:53 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-07-30 14:41:56 -0400 |
commit | f11ac8db5d07b6e99d41ff4aa39d878ee5cef1c5 (patch) | |
tree | 4393cbc2653145ba3269d5143f5db7811a59698b /fs/nfs/inode.c | |
parent | 1f0e890dba5b0f543fea47732116b1c65d55614e (diff) |
NFSv4: Ensure that we track the NFSv4 lock state in read/write requests.
This patch fixes bugzilla entry 14501:
https://bugzilla.kernel.org/show_bug.cgi?id=14501
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 099b3518feea..ec7a8f96a2c2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -530,6 +530,68 @@ out: | |||
530 | return err; | 530 | return err; |
531 | } | 531 | } |
532 | 532 | ||
533 | static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | ||
534 | { | ||
535 | atomic_set(&l_ctx->count, 1); | ||
536 | l_ctx->lockowner = current->files; | ||
537 | l_ctx->pid = current->tgid; | ||
538 | INIT_LIST_HEAD(&l_ctx->list); | ||
539 | } | ||
540 | |||
541 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | ||
542 | { | ||
543 | struct nfs_lock_context *pos; | ||
544 | |||
545 | list_for_each_entry(pos, &ctx->lock_context.list, list) { | ||
546 | if (pos->lockowner != current->files) | ||
547 | continue; | ||
548 | if (pos->pid != current->tgid) | ||
549 | continue; | ||
550 | atomic_inc(&pos->count); | ||
551 | return pos; | ||
552 | } | ||
553 | return NULL; | ||
554 | } | ||
555 | |||
556 | struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) | ||
557 | { | ||
558 | struct nfs_lock_context *res, *new = NULL; | ||
559 | struct inode *inode = ctx->path.dentry->d_inode; | ||
560 | |||
561 | spin_lock(&inode->i_lock); | ||
562 | res = __nfs_find_lock_context(ctx); | ||
563 | if (res == NULL) { | ||
564 | spin_unlock(&inode->i_lock); | ||
565 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
566 | if (new == NULL) | ||
567 | return NULL; | ||
568 | nfs_init_lock_context(new); | ||
569 | spin_lock(&inode->i_lock); | ||
570 | res = __nfs_find_lock_context(ctx); | ||
571 | if (res == NULL) { | ||
572 | list_add_tail(&new->list, &ctx->lock_context.list); | ||
573 | new->open_context = ctx; | ||
574 | res = new; | ||
575 | new = NULL; | ||
576 | } | ||
577 | } | ||
578 | spin_unlock(&inode->i_lock); | ||
579 | kfree(new); | ||
580 | return res; | ||
581 | } | ||
582 | |||
583 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | ||
584 | { | ||
585 | struct nfs_open_context *ctx = l_ctx->open_context; | ||
586 | struct inode *inode = ctx->path.dentry->d_inode; | ||
587 | |||
588 | if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) | ||
589 | return; | ||
590 | list_del(&l_ctx->list); | ||
591 | spin_unlock(&inode->i_lock); | ||
592 | kfree(l_ctx); | ||
593 | } | ||
594 | |||
533 | /** | 595 | /** |
534 | * nfs_close_context - Common close_context() routine NFSv2/v3 | 596 | * nfs_close_context - Common close_context() routine NFSv2/v3 |
535 | * @ctx: pointer to context | 597 | * @ctx: pointer to context |
@@ -566,11 +628,11 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
566 | path_get(&ctx->path); | 628 | path_get(&ctx->path); |
567 | ctx->cred = get_rpccred(cred); | 629 | ctx->cred = get_rpccred(cred); |
568 | ctx->state = NULL; | 630 | ctx->state = NULL; |
569 | ctx->lockowner = current->files; | ||
570 | ctx->flags = 0; | 631 | ctx->flags = 0; |
571 | ctx->error = 0; | 632 | ctx->error = 0; |
572 | ctx->dir_cookie = 0; | 633 | ctx->dir_cookie = 0; |
573 | atomic_set(&ctx->count, 1); | 634 | nfs_init_lock_context(&ctx->lock_context); |
635 | ctx->lock_context.open_context = ctx; | ||
574 | } | 636 | } |
575 | return ctx; | 637 | return ctx; |
576 | } | 638 | } |
@@ -578,7 +640,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
578 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | 640 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) |
579 | { | 641 | { |
580 | if (ctx != NULL) | 642 | if (ctx != NULL) |
581 | atomic_inc(&ctx->count); | 643 | atomic_inc(&ctx->lock_context.count); |
582 | return ctx; | 644 | return ctx; |
583 | } | 645 | } |
584 | 646 | ||
@@ -586,7 +648,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
586 | { | 648 | { |
587 | struct inode *inode = ctx->path.dentry->d_inode; | 649 | struct inode *inode = ctx->path.dentry->d_inode; |
588 | 650 | ||
589 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 651 | if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) |
590 | return; | 652 | return; |
591 | list_del(&ctx->list); | 653 | list_del(&ctx->list); |
592 | spin_unlock(&inode->i_lock); | 654 | spin_unlock(&inode->i_lock); |