summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2013-08-14 11:59:16 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-09-03 15:25:09 -0400
commitdc24826bfca8d788d05f625208f06d90be5560b3 (patch)
treecc6fa221202666ac694581061caf373b431ff9bd /fs/nfs
parent4de6caa270afaa381dd3373e9e6d148b1090e0ec (diff)
NFS avoid expired credential keys for buffered writes
We must avoid buffering a WRITE that is using a credential key (e.g. a GSS context key) that is about to expire or has expired. We currently will paint ourselves into a corner by returning success to the applciation for such a buffered WRITE, only to discover that we do not have permission when we attempt to flush the WRITE (and potentially associated COMMIT) to disk. Use the RPC layer credential key timeout and expire routines which use a a watermark, gss_key_expire_timeo. We test the key in nfs_file_write. If a WRITE is using a credential with a key that will expire within watermark seconds, flush the inode in nfs_write_end and send only NFS_FILE_SYNC WRITEs by adding nfs_ctx_key_to_expire to nfs_need_sync_write. Note that this results in single page NFS_FILE_SYNC WRITEs. Signed-off-by: Andy Adamson <andros@netapp.com> [Trond: removed a pr_warn_ratelimited() for now] Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/file.c15
-rw-r--r--fs/nfs/internal.h2
-rw-r--r--fs/nfs/write.c27
3 files changed, 43 insertions, 1 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index d6a9db0a8545..1e6bfdbc1aff 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -411,6 +411,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
411 struct page *page, void *fsdata) 411 struct page *page, void *fsdata)
412{ 412{
413 unsigned offset = pos & (PAGE_CACHE_SIZE - 1); 413 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
414 struct nfs_open_context *ctx = nfs_file_open_context(file);
414 int status; 415 int status;
415 416
416 dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n", 417 dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n",
@@ -446,6 +447,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
446 if (status < 0) 447 if (status < 0)
447 return status; 448 return status;
448 NFS_I(mapping->host)->write_io += copied; 449 NFS_I(mapping->host)->write_io += copied;
450
451 if (nfs_ctx_key_to_expire(ctx)) {
452 status = nfs_wb_all(mapping->host);
453 if (status < 0)
454 return status;
455 }
456
449 return copied; 457 return copied;
450} 458}
451 459
@@ -642,7 +650,8 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)
642 if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC)) 650 if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC))
643 return 1; 651 return 1;
644 ctx = nfs_file_open_context(filp); 652 ctx = nfs_file_open_context(filp);
645 if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) 653 if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) ||
654 nfs_ctx_key_to_expire(ctx))
646 return 1; 655 return 1;
647 return 0; 656 return 0;
648} 657}
@@ -656,6 +665,10 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
656 ssize_t result; 665 ssize_t result;
657 size_t count = iov_length(iov, nr_segs); 666 size_t count = iov_length(iov, nr_segs);
658 667
668 result = nfs_key_timeout_notify(iocb->ki_filp, inode);
669 if (result)
670 return result;
671
659 if (iocb->ki_filp->f_flags & O_DIRECT) 672 if (iocb->ki_filp->f_flags & O_DIRECT)
660 return nfs_file_direct_write(iocb, iov, nr_segs, pos, true); 673 return nfs_file_direct_write(iocb, iov, nr_segs, pos, true);
661 674
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 50f7068903b9..2415198d29ad 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -431,6 +431,8 @@ void nfs_request_remove_commit_list(struct nfs_page *req,
431void nfs_init_cinfo(struct nfs_commit_info *cinfo, 431void nfs_init_cinfo(struct nfs_commit_info *cinfo,
432 struct inode *inode, 432 struct inode *inode,
433 struct nfs_direct_req *dreq); 433 struct nfs_direct_req *dreq);
434int nfs_key_timeout_notify(struct file *filp, struct inode *inode);
435bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx);
434 436
435#ifdef CONFIG_MIGRATION 437#ifdef CONFIG_MIGRATION
436extern int nfs_migrate_page(struct address_space *, 438extern int nfs_migrate_page(struct address_space *,
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index d37e8ca9ab86..94eb4504731a 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -876,6 +876,33 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
876} 876}
877 877
878/* 878/*
879 * Avoid buffered writes when a open context credential's key would
880 * expire soon.
881 *
882 * Returns -EACCES if the key will expire within RPC_KEY_EXPIRE_FAIL.
883 *
884 * Return 0 and set a credential flag which triggers the inode to flush
885 * and performs NFS_FILE_SYNC writes if the key will expired within
886 * RPC_KEY_EXPIRE_TIMEO.
887 */
888int
889nfs_key_timeout_notify(struct file *filp, struct inode *inode)
890{
891 struct nfs_open_context *ctx = nfs_file_open_context(filp);
892 struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth;
893
894 return rpcauth_key_timeout_notify(auth, ctx->cred);
895}
896
897/*
898 * Test if the open context credential key is marked to expire soon.
899 */
900bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
901{
902 return rpcauth_cred_key_to_expire(ctx->cred);
903}
904
905/*
879 * If the page cache is marked as unsafe or invalid, then we can't rely on 906 * If the page cache is marked as unsafe or invalid, then we can't rely on
880 * the PageUptodate() flag. In this case, we will need to turn off 907 * the PageUptodate() flag. In this case, we will need to turn off
881 * write optimisations that depend on the page contents being correct. 908 * write optimisations that depend on the page contents being correct.