@@ -345,6 +345,7 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
int ret;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
struct page *page;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
int once_thru = 0;
dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n",
@@ -362,6 +363,10 @@ start:
if (ret)
return ret;
+ ret = nfs_ctx_key_timeout_notify(ctx);
+ if (ret)
+ return ret;
+
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page)
return -ENOMEM;
@@ -387,6 +392,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
struct page *page, void *fsdata)
{
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
int status;
dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n",
@@ -422,6 +428,10 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
if (status < 0)
return status;
NFS_I(mapping->host)->write_io += copied;
+
+ if (nfs_ctx_key_to_expire(ctx))
+ nfs_wb_all(mapping->host);
+
return copied;
}
@@ -449,6 +449,8 @@ void nfs_request_remove_commit_list(struct nfs_page *req,
void nfs_init_cinfo(struct nfs_commit_info *cinfo,
struct inode *inode,
struct nfs_direct_req *dreq);
+int nfs_ctx_key_timeout_notify(struct nfs_open_context *ctx);
+bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx);
#ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *,
@@ -872,6 +872,32 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
}
/*
+ * Avoid buffered writes when a open context credential's key would
+ * expire soon.
+ *
+ * Returns -EACCES if the key will expire within RPC_KEY_EXPIRE_FAIL.
+ *
+ * Return 0 and set a credential flag which triggers the inode to flush
+ * and performs NFS_FILE_SYNC writes if the key will expired within
+ * RPC_KEY_EXPIRE_TIMEO.
+ */
+int
+nfs_ctx_key_timeout_notify(struct nfs_open_context *ctx)
+{
+ struct rpc_auth *auth = NFS_SERVER(ctx->state->inode)->client->cl_auth;
+
+ return rpcauth_key_timeout_notify(auth, ctx->cred);
+}
+
+/*
+ * Test if the open context credential key is marked to expire soon.
+ */
+bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
+{
+ return rpcauth_cred_key_to_expire(ctx->cred);
+}
+
+/*
* If the page cache is marked as unsafe or invalid, then we can't rely on
* the PageUptodate() flag. In this case, we will need to turn off
* write optimisations that depend on the page contents being correct.
@@ -1024,6 +1050,9 @@ static void nfs_write_rpcsetup(struct nfs_write_data *data,
data->args.stable = NFS_FILE_SYNC;
}
+ if (nfs_ctx_key_to_expire(data->args.context))
+ data->args.stable = NFS_FILE_SYNC;
+
data->res.fattr = &data->fattr;
data->res.count = count;
data->res.verf = &data->verf;