Merge tag 'nfs-for-5.2-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker: "Highlights include: Stable bugfixes: - Fall back to MDS if no deviceid is found rather than aborting # v4.11+ - NFS4: Fix v4.0 client state corruption when mount Features: - Much improved handling of soft mounts with NFS v4.0: - Reduce risk of false positive timeouts - Faster failover of reads and writes after a timeout - Added a "softerr" mount option to return ETIMEDOUT instead of EIO to the application after a timeout - Increase number of xprtrdma backchannel requests - Add additional xprtrdma tracepoints - Improved send completion batching for xprtrdma Other bugfixes and cleanups: - Return -EINVAL when NFS v4.2 is passed an invalid dedup mode - Reduce usage of GFP_ATOMIC pages in SUNRPC - Various minor NFS over RDMA cleanups and bugfixes - Use the correct container namespace for upcalls - Don't share superblocks between user namespaces - Various other container fixes - Make nfs_match_client() killable to prevent soft lockups - Don't mark all open state for recovery when handling recallable state revoked flag" * tag 'nfs-for-5.2-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (69 commits) SUNRPC: Rebalance a kref in auth_gss.c NFS: Fix a double unlock from nfs_match,get_client nfs: pass the correct prototype to read_cache_page NFSv4: don't mark all open state for recovery when handling recallable state revoked flag SUNRPC: Fix an error code in gss_alloc_msg() SUNRPC: task should be exit if encode return EKEYEXPIRED more times NFS4: Fix v4.0 client state corruption when mount PNFS fallback to MDS if no deviceid found NFS: make nfs_match_client killable lockd: Store the lockd client credential in struct nlm_host NFS: When mounting, don't share filesystems between different user namespaces NFS: Convert NFSv2 to use the container user namespace NFSv4: Convert the NFS client idmapper to use the container user namespace NFS: Convert NFSv3 to use the container user namespace SUNRPC: Use namespace of listening daemon in the client AUTH_GSS upcall SUNRPC: Use the client user namespace when encoding creds NFS: Store the credential of the mount process in the nfs_server SUNRPC: Cache cred of process creating the rpc_client xprtrdma: Remove stale comment xprtrdma: Update comments that reference ib_drain_qp ...
This commit is contained in:
@@ -284,6 +284,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
|
||||
struct nfs_client *clp;
|
||||
const struct sockaddr *sap = data->addr;
|
||||
struct nfs_net *nn = net_generic(data->net, nfs_net_id);
|
||||
int error;
|
||||
|
||||
again:
|
||||
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
|
||||
@@ -296,9 +297,11 @@ again:
|
||||
if (clp->cl_cons_state > NFS_CS_READY) {
|
||||
refcount_inc(&clp->cl_count);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
nfs_wait_client_init_complete(clp);
|
||||
error = nfs_wait_client_init_complete(clp);
|
||||
nfs_put_client(clp);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
if (error < 0)
|
||||
return ERR_PTR(error);
|
||||
goto again;
|
||||
}
|
||||
|
||||
@@ -407,6 +410,8 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
|
||||
clp = nfs_match_client(cl_init);
|
||||
if (clp) {
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
if (IS_ERR(clp))
|
||||
return clp;
|
||||
if (new)
|
||||
new->rpc_ops->free_client(new);
|
||||
return nfs_found_client(cl_init, clp);
|
||||
@@ -500,6 +505,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
|
||||
.program = &nfs_program,
|
||||
.version = clp->rpc_ops->version,
|
||||
.authflavor = flavor,
|
||||
.cred = cl_init->cred,
|
||||
};
|
||||
|
||||
if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
|
||||
@@ -598,6 +604,8 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
|
||||
sizeof(server->client->cl_timeout_default));
|
||||
server->client->cl_timeout = &server->client->cl_timeout_default;
|
||||
server->client->cl_softrtry = 0;
|
||||
if (server->flags & NFS_MOUNT_SOFTERR)
|
||||
server->client->cl_softerr = 1;
|
||||
if (server->flags & NFS_MOUNT_SOFT)
|
||||
server->client->cl_softrtry = 1;
|
||||
|
||||
@@ -652,6 +660,7 @@ static int nfs_init_server(struct nfs_server *server,
|
||||
.proto = data->nfs_server.protocol,
|
||||
.net = data->net,
|
||||
.timeparms = &timeparms,
|
||||
.cred = server->cred,
|
||||
};
|
||||
struct nfs_client *clp;
|
||||
int error;
|
||||
@@ -920,6 +929,7 @@ void nfs_free_server(struct nfs_server *server)
|
||||
ida_destroy(&server->lockowner_id);
|
||||
ida_destroy(&server->openowner_id);
|
||||
nfs_free_iostats(server->io_stats);
|
||||
put_cred(server->cred);
|
||||
kfree(server);
|
||||
nfs_release_automount_timer();
|
||||
}
|
||||
@@ -940,6 +950,8 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
|
||||
if (!server)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
server->cred = get_cred(current_cred());
|
||||
|
||||
error = -ENOMEM;
|
||||
fattr = nfs_alloc_fattr();
|
||||
if (fattr == NULL)
|
||||
@@ -1006,6 +1018,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
|
||||
if (!server)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
server->cred = get_cred(source->cred);
|
||||
|
||||
error = -ENOMEM;
|
||||
fattr_fsinfo = nfs_alloc_fattr();
|
||||
if (fattr_fsinfo == NULL)
|
||||
|
@@ -1033,6 +1033,18 @@ void nfs_mark_test_expired_all_delegations(struct nfs_client *clp)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_test_expired_all_delegations - test all delegations for a client
|
||||
* @clp: nfs_client to process
|
||||
*
|
||||
* Helper for handling "recallable state revoked" status from server.
|
||||
*/
|
||||
void nfs_test_expired_all_delegations(struct nfs_client *clp)
|
||||
{
|
||||
nfs_mark_test_expired_all_delegations(clp);
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_reap_expired_delegations - reap expired delegations
|
||||
* @clp: nfs_client to process
|
||||
|
@@ -58,6 +58,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp);
|
||||
void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
|
||||
|
||||
void nfs_mark_test_expired_all_delegations(struct nfs_client *clp);
|
||||
void nfs_test_expired_all_delegations(struct nfs_client *clp);
|
||||
void nfs_reap_expired_delegations(struct nfs_client *clp);
|
||||
|
||||
/* NFSv4 delegation-related procedures */
|
||||
|
@@ -714,8 +714,9 @@ out:
|
||||
* We only need to convert from xdr once so future lookups are much simpler
|
||||
*/
|
||||
static
|
||||
int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
|
||||
int nfs_readdir_filler(void *data, struct page* page)
|
||||
{
|
||||
nfs_readdir_descriptor_t *desc = data;
|
||||
struct inode *inode = file_inode(desc->file);
|
||||
int ret;
|
||||
|
||||
@@ -762,8 +763,8 @@ void cache_page_release(nfs_readdir_descriptor_t *desc)
|
||||
static
|
||||
struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
|
||||
{
|
||||
return read_cache_page(desc->file->f_mapping,
|
||||
desc->page_index, (filler_t *)nfs_readdir_filler, desc);
|
||||
return read_cache_page(desc->file->f_mapping, desc->page_index,
|
||||
nfs_readdir_filler, desc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -492,7 +492,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
|
||||
struct nfs_page *req;
|
||||
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
|
||||
/* XXX do we need to do the eof zeroing found in async_filler? */
|
||||
req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
|
||||
req = nfs_create_request(dreq->ctx, pagevec[i],
|
||||
pgbase, req_len);
|
||||
if (IS_ERR(req)) {
|
||||
result = PTR_ERR(req);
|
||||
@@ -663,6 +663,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
|
||||
/* Bump the transmission count */
|
||||
req->wb_nio++;
|
||||
if (!nfs_pageio_add_request(&desc, req)) {
|
||||
nfs_list_move_request(req, &failed);
|
||||
spin_lock(&cinfo.inode->i_lock);
|
||||
@@ -703,6 +705,11 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
|
||||
req = nfs_list_entry(data->pages.next);
|
||||
nfs_list_remove_request(req);
|
||||
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) {
|
||||
/*
|
||||
* Despite the reboot, the write was successful,
|
||||
* so reset wb_nio.
|
||||
*/
|
||||
req->wb_nio = 0;
|
||||
/* Note the rewrite will go through mds */
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
} else
|
||||
@@ -899,7 +906,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
|
||||
struct nfs_page *req;
|
||||
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
|
||||
|
||||
req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
|
||||
req = nfs_create_request(dreq->ctx, pagevec[i],
|
||||
pgbase, req_len);
|
||||
if (IS_ERR(req)) {
|
||||
result = PTR_ERR(req);
|
||||
|
@@ -147,7 +147,7 @@ nfs_file_flush(struct file *file, fl_owner_t id)
|
||||
return 0;
|
||||
|
||||
/* Flush writes to the server and return any errors */
|
||||
return vfs_fsync(file, 0);
|
||||
return nfs_wb_all(inode);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
@@ -199,13 +199,6 @@ EXPORT_SYMBOL_GPL(nfs_file_mmap);
|
||||
* Flush any dirty pages for this process, and check for write errors.
|
||||
* The return status from this call provides a reliable indication of
|
||||
* whether any write errors occurred for this process.
|
||||
*
|
||||
* Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
|
||||
* disk, but it retrieves and clears ctx->error after synching, despite
|
||||
* the two being set at the same time in nfs_context_set_write_error().
|
||||
* This is because the former is used to notify the _next_ call to
|
||||
* nfs_file_write() that a write error occurred, and hence cause it to
|
||||
* fall back to doing a synchronous write.
|
||||
*/
|
||||
static int
|
||||
nfs_file_fsync_commit(struct file *file, int datasync)
|
||||
@@ -220,11 +213,8 @@ nfs_file_fsync_commit(struct file *file, int datasync)
|
||||
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
|
||||
do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
|
||||
status = nfs_commit_inode(inode, FLUSH_SYNC);
|
||||
if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) {
|
||||
ret = xchg(&ctx->error, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (status == 0)
|
||||
status = file_check_and_advance_wb_err(file);
|
||||
if (status < 0) {
|
||||
ret = status;
|
||||
goto out;
|
||||
@@ -245,13 +235,7 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
trace_nfs_fsync_enter(inode);
|
||||
|
||||
do {
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(file);
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
||||
if (test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) {
|
||||
int ret2 = xchg(&ctx->error, 0);
|
||||
if (ret2)
|
||||
ret = ret2;
|
||||
}
|
||||
ret = file_write_and_wait_range(file, start, end);
|
||||
if (ret != 0)
|
||||
break;
|
||||
ret = nfs_file_fsync_commit(file, datasync);
|
||||
@@ -600,8 +584,7 @@ static int nfs_need_check_write(struct file *filp, struct inode *inode)
|
||||
struct nfs_open_context *ctx;
|
||||
|
||||
ctx = nfs_file_open_context(filp);
|
||||
if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) ||
|
||||
nfs_ctx_key_to_expire(ctx, inode))
|
||||
if (nfs_ctx_key_to_expire(ctx, inode))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -655,7 +638,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
|
||||
/* Return error values */
|
||||
if (nfs_need_check_write(file, inode)) {
|
||||
int err = vfs_fsync(file, 0);
|
||||
int err = nfs_wb_all(inode);
|
||||
if (err < 0)
|
||||
result = err;
|
||||
}
|
||||
@@ -709,7 +692,7 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
|
||||
* Flush all pending writes before doing anything
|
||||
* with locks..
|
||||
*/
|
||||
vfs_fsync(filp, 0);
|
||||
nfs_wb_all(inode);
|
||||
|
||||
l_ctx = nfs_get_lock_context(nfs_file_open_context(filp));
|
||||
if (!IS_ERR(l_ctx)) {
|
||||
|
@@ -904,7 +904,7 @@ fl_pnfs_update_layout(struct inode *ino,
|
||||
status = filelayout_check_deviceid(lo, fl, gfp_flags);
|
||||
if (status) {
|
||||
pnfs_put_lseg(lseg);
|
||||
lseg = ERR_PTR(status);
|
||||
lseg = NULL;
|
||||
}
|
||||
out:
|
||||
return lseg;
|
||||
@@ -917,7 +917,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
|
||||
pnfs_generic_pg_check_layout(pgio);
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_READ,
|
||||
@@ -944,7 +944,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
|
||||
pnfs_generic_pg_check_layout(pgio);
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_RW,
|
||||
|
@@ -28,6 +28,8 @@
|
||||
#define FF_LAYOUT_POLL_RETRY_MAX (15*HZ)
|
||||
#define FF_LAYOUTRETURN_MAXERR 20
|
||||
|
||||
static unsigned short io_maxretrans;
|
||||
|
||||
static void ff_layout_read_record_layoutstats_done(struct rpc_task *task,
|
||||
struct nfs_pgio_header *hdr);
|
||||
static int ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
|
||||
@@ -871,7 +873,7 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,
|
||||
{
|
||||
pnfs_put_lseg(pgio->pg_lseg);
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_READ,
|
||||
@@ -925,6 +927,7 @@ retry:
|
||||
pgm = &pgio->pg_mirrors[0];
|
||||
pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
|
||||
|
||||
pgio->pg_maxretrans = io_maxretrans;
|
||||
return;
|
||||
out_nolseg:
|
||||
if (pgio->pg_error < 0)
|
||||
@@ -950,7 +953,7 @@ retry:
|
||||
pnfs_generic_pg_check_layout(pgio);
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_RW,
|
||||
@@ -992,6 +995,7 @@ retry:
|
||||
pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
|
||||
}
|
||||
|
||||
pgio->pg_maxretrans = io_maxretrans;
|
||||
return;
|
||||
|
||||
out_mds:
|
||||
@@ -1006,7 +1010,7 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
|
||||
{
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_RW,
|
||||
@@ -2515,3 +2519,7 @@ MODULE_DESCRIPTION("The NFSv4 flexfile layout driver");
|
||||
|
||||
module_init(nfs4flexfilelayout_init);
|
||||
module_exit(nfs4flexfilelayout_exit);
|
||||
|
||||
module_param(io_maxretrans, ushort, 0644);
|
||||
MODULE_PARM_DESC(io_maxretrans, "The number of times the NFSv4.1 client "
|
||||
"retries an I/O request before returning an error. ");
|
||||
|
@@ -885,10 +885,14 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
|
||||
spin_lock(&inode->i_lock);
|
||||
res = __nfs_find_lock_context(ctx);
|
||||
if (res == NULL) {
|
||||
list_add_tail_rcu(&new->list, &ctx->lock_context.list);
|
||||
new->open_context = ctx;
|
||||
res = new;
|
||||
new = NULL;
|
||||
new->open_context = get_nfs_open_context(ctx);
|
||||
if (new->open_context) {
|
||||
list_add_tail_rcu(&new->list,
|
||||
&ctx->lock_context.list);
|
||||
res = new;
|
||||
new = NULL;
|
||||
} else
|
||||
res = ERR_PTR(-EBADF);
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
kfree(new);
|
||||
@@ -906,6 +910,7 @@ void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
|
||||
return;
|
||||
list_del_rcu(&l_ctx->list);
|
||||
spin_unlock(&inode->i_lock);
|
||||
put_nfs_open_context(ctx);
|
||||
kfree_rcu(l_ctx, rcu_head);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_put_lock_context);
|
||||
|
@@ -84,6 +84,7 @@ struct nfs_client_initdata {
|
||||
u32 minorversion;
|
||||
struct net *net;
|
||||
const struct rpc_timeout *timeparms;
|
||||
const struct cred *cred;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -766,15 +767,10 @@ static inline bool nfs_error_is_fatal(int err)
|
||||
case -ESTALE:
|
||||
case -E2BIG:
|
||||
case -ENOMEM:
|
||||
case -ETIMEDOUT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
|
||||
{
|
||||
ctx->error = error;
|
||||
smp_wmb();
|
||||
set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
|
||||
}
|
||||
|
@@ -163,6 +163,7 @@ int nfs_mount(struct nfs_mount_request *info)
|
||||
.program = &mnt_program,
|
||||
.version = info->version,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.cred = current_cred(),
|
||||
};
|
||||
struct rpc_clnt *mnt_clnt;
|
||||
int status;
|
||||
@@ -249,6 +250,7 @@ void nfs_umount(const struct nfs_mount_request *info)
|
||||
.version = info->version,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = RPC_CLNT_CREATE_NOPING,
|
||||
.cred = current_cred(),
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = info->dirpath,
|
||||
|
@@ -76,6 +76,20 @@ static int nfs_stat_to_errno(enum nfs_stat);
|
||||
* or decoded inline.
|
||||
*/
|
||||
|
||||
static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
|
||||
{
|
||||
if (clnt && clnt->cl_cred)
|
||||
return clnt->cl_cred->user_ns;
|
||||
return &init_user_ns;
|
||||
}
|
||||
|
||||
static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
|
||||
{
|
||||
if (rqstp->rq_task)
|
||||
return rpc_userns(rqstp->rq_task->tk_client);
|
||||
return &init_user_ns;
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef opaque nfsdata<>;
|
||||
*/
|
||||
@@ -248,7 +262,8 @@ static __be32 *xdr_decode_time(__be32 *p, struct timespec *timep)
|
||||
* };
|
||||
*
|
||||
*/
|
||||
static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
u32 rdev, type;
|
||||
__be32 *p;
|
||||
@@ -263,10 +278,10 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
|
||||
fattr->mode = be32_to_cpup(p++);
|
||||
fattr->nlink = be32_to_cpup(p++);
|
||||
fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++));
|
||||
fattr->uid = make_kuid(userns, be32_to_cpup(p++));
|
||||
if (!uid_valid(fattr->uid))
|
||||
goto out_uid;
|
||||
fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++));
|
||||
fattr->gid = make_kgid(userns, be32_to_cpup(p++));
|
||||
if (!gid_valid(fattr->gid))
|
||||
goto out_gid;
|
||||
|
||||
@@ -321,7 +336,8 @@ static __be32 *xdr_time_not_set(__be32 *p)
|
||||
return p;
|
||||
}
|
||||
|
||||
static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
|
||||
static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
struct timespec ts;
|
||||
__be32 *p;
|
||||
@@ -333,11 +349,11 @@ static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
|
||||
else
|
||||
*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
|
||||
if (attr->ia_valid & ATTR_UID)
|
||||
*p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid));
|
||||
*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
|
||||
else
|
||||
*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
|
||||
if (attr->ia_valid & ATTR_GID)
|
||||
*p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid));
|
||||
*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
|
||||
else
|
||||
*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
@@ -451,7 +467,8 @@ out_cheating:
|
||||
* };
|
||||
*/
|
||||
static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
|
||||
__u32 *op_status)
|
||||
__u32 *op_status,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -463,7 +480,7 @@ static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
|
||||
*op_status = status;
|
||||
if (status != NFS_OK)
|
||||
goto out_default;
|
||||
error = decode_fattr(xdr, result);
|
||||
error = decode_fattr(xdr, result, userns);
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
@@ -498,19 +515,21 @@ static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
|
||||
* void;
|
||||
* };
|
||||
*/
|
||||
static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
|
||||
static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = decode_fhandle(xdr, result->fh);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_fattr(xdr, result->fattr);
|
||||
error = decode_fattr(xdr, result->fattr, userns);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
|
||||
static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -520,7 +539,7 @@ static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
|
||||
goto out;
|
||||
if (status != NFS_OK)
|
||||
goto out_default;
|
||||
error = decode_diropok(xdr, result);
|
||||
error = decode_diropok(xdr, result, userns);
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
@@ -559,7 +578,7 @@ static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
|
||||
const struct nfs_sattrargs *args = data;
|
||||
|
||||
encode_fhandle(xdr, args->fh);
|
||||
encode_sattr(xdr, args->sattr);
|
||||
encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
|
||||
@@ -674,7 +693,7 @@ static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
|
||||
const struct nfs_createargs *args = data;
|
||||
|
||||
encode_diropargs(xdr, args->fh, args->name, args->len);
|
||||
encode_sattr(xdr, args->sattr);
|
||||
encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
|
||||
@@ -741,7 +760,7 @@ static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
|
||||
|
||||
encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
|
||||
encode_path(xdr, args->pages, args->pathlen);
|
||||
encode_sattr(xdr, args->sattr);
|
||||
encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -803,13 +822,13 @@ out_default:
|
||||
static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
void *result)
|
||||
{
|
||||
return decode_attrstat(xdr, result, NULL);
|
||||
return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
void *result)
|
||||
{
|
||||
return decode_diropres(xdr, result);
|
||||
return decode_diropres(xdr, result, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -864,7 +883,7 @@ static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
result->op_status = status;
|
||||
if (status != NFS_OK)
|
||||
goto out_default;
|
||||
error = decode_fattr(xdr, result->fattr);
|
||||
error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_nfsdata(xdr, result);
|
||||
@@ -881,7 +900,8 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
|
||||
/* All NFSv2 writes are "file sync" writes */
|
||||
result->verf->committed = NFS_FILE_SYNC;
|
||||
return decode_attrstat(xdr, result->fattr, &result->op_status);
|
||||
return decode_attrstat(xdr, result->fattr, &result->op_status,
|
||||
rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -91,6 +91,7 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
|
||||
.proto = ds_proto,
|
||||
.net = mds_clp->cl_net,
|
||||
.timeparms = &ds_timeout,
|
||||
.cred = mds_srv->cred,
|
||||
};
|
||||
struct nfs_client *clp;
|
||||
char buf[INET6_ADDRSTRLEN + 1];
|
||||
|
142
fs/nfs/nfs3xdr.c
142
fs/nfs/nfs3xdr.c
@@ -104,6 +104,20 @@ static const umode_t nfs_type2fmt[] = {
|
||||
[NF3FIFO] = S_IFIFO,
|
||||
};
|
||||
|
||||
static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
|
||||
{
|
||||
if (clnt && clnt->cl_cred)
|
||||
return clnt->cl_cred->user_ns;
|
||||
return &init_user_ns;
|
||||
}
|
||||
|
||||
static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
|
||||
{
|
||||
if (rqstp->rq_task)
|
||||
return rpc_userns(rqstp->rq_task->tk_client);
|
||||
return &init_user_ns;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode/decode NFSv3 basic data types
|
||||
*
|
||||
@@ -516,7 +530,8 @@ static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep)
|
||||
* set_mtime mtime;
|
||||
* };
|
||||
*/
|
||||
static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
|
||||
static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
struct timespec ts;
|
||||
u32 nbytes;
|
||||
@@ -551,13 +566,13 @@ static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
|
||||
|
||||
if (attr->ia_valid & ATTR_UID) {
|
||||
*p++ = xdr_one;
|
||||
*p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid));
|
||||
*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
|
||||
} else
|
||||
*p++ = xdr_zero;
|
||||
|
||||
if (attr->ia_valid & ATTR_GID) {
|
||||
*p++ = xdr_one;
|
||||
*p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid));
|
||||
*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
|
||||
} else
|
||||
*p++ = xdr_zero;
|
||||
|
||||
@@ -606,7 +621,8 @@ static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
|
||||
* nfstime3 ctime;
|
||||
* };
|
||||
*/
|
||||
static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
umode_t fmode;
|
||||
__be32 *p;
|
||||
@@ -619,10 +635,10 @@ static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
|
||||
fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
|
||||
fattr->nlink = be32_to_cpup(p++);
|
||||
fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++));
|
||||
fattr->uid = make_kuid(userns, be32_to_cpup(p++));
|
||||
if (!uid_valid(fattr->uid))
|
||||
goto out_uid;
|
||||
fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++));
|
||||
fattr->gid = make_kgid(userns, be32_to_cpup(p++));
|
||||
if (!gid_valid(fattr->gid))
|
||||
goto out_gid;
|
||||
|
||||
@@ -659,7 +675,8 @@ out_gid:
|
||||
* void;
|
||||
* };
|
||||
*/
|
||||
static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
@@ -667,7 +684,7 @@ static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
if (unlikely(!p))
|
||||
return -EIO;
|
||||
if (*p != xdr_zero)
|
||||
return decode_fattr3(xdr, fattr);
|
||||
return decode_fattr3(xdr, fattr, userns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -728,14 +745,15 @@ static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
||||
static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = decode_pre_op_attr(xdr, fattr);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, fattr);
|
||||
error = decode_post_op_attr(xdr, fattr, userns);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
@@ -837,7 +855,7 @@ static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
|
||||
{
|
||||
const struct nfs3_sattrargs *args = data;
|
||||
encode_nfs_fh3(xdr, args->fh);
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
|
||||
encode_sattrguard3(xdr, args);
|
||||
}
|
||||
|
||||
@@ -998,13 +1016,14 @@ static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static void encode_createhow3(struct xdr_stream *xdr,
|
||||
const struct nfs3_createargs *args)
|
||||
const struct nfs3_createargs *args,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
encode_uint32(xdr, args->createmode);
|
||||
switch (args->createmode) {
|
||||
case NFS3_CREATE_UNCHECKED:
|
||||
case NFS3_CREATE_GUARDED:
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, userns);
|
||||
break;
|
||||
case NFS3_CREATE_EXCLUSIVE:
|
||||
encode_createverf3(xdr, args->verifier);
|
||||
@@ -1021,7 +1040,7 @@ static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
|
||||
const struct nfs3_createargs *args = data;
|
||||
|
||||
encode_diropargs3(xdr, args->fh, args->name, args->len);
|
||||
encode_createhow3(xdr, args);
|
||||
encode_createhow3(xdr, args, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1039,7 +1058,7 @@ static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
|
||||
const struct nfs3_mkdirargs *args = data;
|
||||
|
||||
encode_diropargs3(xdr, args->fh, args->name, args->len);
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1056,11 +1075,12 @@ static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static void encode_symlinkdata3(struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
const void *data,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
const struct nfs3_symlinkargs *args = data;
|
||||
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, userns);
|
||||
encode_nfspath3(xdr, args->pages, args->pathlen);
|
||||
}
|
||||
|
||||
@@ -1071,7 +1091,7 @@ static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
|
||||
const struct nfs3_symlinkargs *args = data;
|
||||
|
||||
encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
|
||||
encode_symlinkdata3(xdr, args);
|
||||
encode_symlinkdata3(xdr, args, rpc_rqst_userns(req));
|
||||
xdr->buf->flags |= XDRBUF_WRITE;
|
||||
}
|
||||
|
||||
@@ -1100,24 +1120,26 @@ static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static void encode_devicedata3(struct xdr_stream *xdr,
|
||||
const struct nfs3_mknodargs *args)
|
||||
const struct nfs3_mknodargs *args,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, userns);
|
||||
encode_specdata3(xdr, args->rdev);
|
||||
}
|
||||
|
||||
static void encode_mknoddata3(struct xdr_stream *xdr,
|
||||
const struct nfs3_mknodargs *args)
|
||||
const struct nfs3_mknodargs *args,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
encode_ftype3(xdr, args->type);
|
||||
switch (args->type) {
|
||||
case NF3CHR:
|
||||
case NF3BLK:
|
||||
encode_devicedata3(xdr, args);
|
||||
encode_devicedata3(xdr, args, userns);
|
||||
break;
|
||||
case NF3SOCK:
|
||||
case NF3FIFO:
|
||||
encode_sattr3(xdr, args->sattr);
|
||||
encode_sattr3(xdr, args->sattr, userns);
|
||||
break;
|
||||
case NF3REG:
|
||||
case NF3DIR:
|
||||
@@ -1134,7 +1156,7 @@ static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
|
||||
const struct nfs3_mknodargs *args = data;
|
||||
|
||||
encode_diropargs3(xdr, args->fh, args->name, args->len);
|
||||
encode_mknoddata3(xdr, args);
|
||||
encode_mknoddata3(xdr, args, rpc_rqst_userns(req));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1379,7 +1401,7 @@ static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
goto out_default;
|
||||
error = decode_fattr3(xdr, result);
|
||||
error = decode_fattr3(xdr, result, rpc_rqst_userns(req));
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
@@ -1414,7 +1436,7 @@ static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result);
|
||||
error = decode_wcc_data(xdr, result, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1449,6 +1471,7 @@ static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct user_namespace *userns = rpc_rqst_userns(req);
|
||||
struct nfs3_diropres *result = data;
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -1461,14 +1484,14 @@ static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
|
||||
error = decode_nfs_fh3(xdr, result->fh);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->dir_attr);
|
||||
error = decode_post_op_attr(xdr, result->dir_attr, userns);
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
error = decode_post_op_attr(xdr, result->dir_attr);
|
||||
error = decode_post_op_attr(xdr, result->dir_attr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
return nfs3_stat_to_errno(status);
|
||||
@@ -1504,7 +1527,7 @@ static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1545,7 +1568,7 @@ static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result);
|
||||
error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1623,7 +1646,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
result->op_status = status;
|
||||
@@ -1694,7 +1717,7 @@ static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->fattr);
|
||||
error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
result->op_status = status;
|
||||
@@ -1728,14 +1751,15 @@ out_status:
|
||||
* };
|
||||
*/
|
||||
static int decode_create3resok(struct xdr_stream *xdr,
|
||||
struct nfs3_diropres *result)
|
||||
struct nfs3_diropres *result,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = decode_post_op_fh3(xdr, result->fh);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
/* The server isn't required to return a file handle.
|
||||
@@ -1744,7 +1768,7 @@ static int decode_create3resok(struct xdr_stream *xdr,
|
||||
* values for the new object. */
|
||||
if (result->fh->size == 0)
|
||||
result->fattr->valid = 0;
|
||||
error = decode_wcc_data(xdr, result->dir_attr);
|
||||
error = decode_wcc_data(xdr, result->dir_attr, userns);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
@@ -1753,6 +1777,7 @@ static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct user_namespace *userns = rpc_rqst_userns(req);
|
||||
struct nfs3_diropres *result = data;
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -1762,11 +1787,11 @@ static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
goto out_default;
|
||||
error = decode_create3resok(xdr, result);
|
||||
error = decode_create3resok(xdr, result, userns);
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
error = decode_wcc_data(xdr, result->dir_attr);
|
||||
error = decode_wcc_data(xdr, result->dir_attr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
return nfs3_stat_to_errno(status);
|
||||
@@ -1801,7 +1826,7 @@ static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->dir_attr);
|
||||
error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1836,6 +1861,7 @@ static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct user_namespace *userns = rpc_rqst_userns(req);
|
||||
struct nfs_renameres *result = data;
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -1843,10 +1869,10 @@ static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->old_fattr);
|
||||
error = decode_wcc_data(xdr, result->old_fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->new_fattr);
|
||||
error = decode_wcc_data(xdr, result->new_fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1880,6 +1906,7 @@ out_status:
|
||||
static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct user_namespace *userns = rpc_rqst_userns(req);
|
||||
struct nfs3_linkres *result = data;
|
||||
enum nfs_stat status;
|
||||
int error;
|
||||
@@ -1887,10 +1914,10 @@ static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->dir_attr);
|
||||
error = decode_wcc_data(xdr, result->dir_attr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -1939,6 +1966,7 @@ out_status:
|
||||
int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||
bool plus)
|
||||
{
|
||||
struct user_namespace *userns = rpc_userns(entry->server->client);
|
||||
struct nfs_entry old = *entry;
|
||||
__be32 *p;
|
||||
int error;
|
||||
@@ -1973,7 +2001,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||
|
||||
if (plus) {
|
||||
entry->fattr->valid = 0;
|
||||
error = decode_post_op_attr(xdr, entry->fattr);
|
||||
error = decode_post_op_attr(xdr, entry->fattr, userns);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
|
||||
@@ -2045,11 +2073,12 @@ static int decode_dirlist3(struct xdr_stream *xdr)
|
||||
}
|
||||
|
||||
static int decode_readdir3resok(struct xdr_stream *xdr,
|
||||
struct nfs3_readdirres *result)
|
||||
struct nfs3_readdirres *result,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = decode_post_op_attr(xdr, result->dir_attr);
|
||||
error = decode_post_op_attr(xdr, result->dir_attr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
/* XXX: do we need to check if result->verf != NULL ? */
|
||||
@@ -2074,11 +2103,11 @@ static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
goto out_default;
|
||||
error = decode_readdir3resok(xdr, result);
|
||||
error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req));
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
error = decode_post_op_attr(xdr, result->dir_attr);
|
||||
error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
return nfs3_stat_to_errno(status);
|
||||
@@ -2138,7 +2167,7 @@ static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -2212,7 +2241,7 @@ static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -2273,7 +2302,7 @@ static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
@@ -2315,7 +2344,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
|
||||
error = decode_nfsstat3(xdr, &status);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_wcc_data(xdr, result->fattr);
|
||||
error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
result->op_status = status;
|
||||
@@ -2331,14 +2360,15 @@ out_status:
|
||||
#ifdef CONFIG_NFS_V3_ACL
|
||||
|
||||
static inline int decode_getacl3resok(struct xdr_stream *xdr,
|
||||
struct nfs3_getaclres *result)
|
||||
struct nfs3_getaclres *result,
|
||||
struct user_namespace *userns)
|
||||
{
|
||||
struct posix_acl **acl;
|
||||
unsigned int *aclcnt;
|
||||
size_t hdrlen;
|
||||
int error;
|
||||
|
||||
error = decode_post_op_attr(xdr, result->fattr);
|
||||
error = decode_post_op_attr(xdr, result->fattr, userns);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
error = decode_uint32(xdr, &result->mask);
|
||||
@@ -2386,7 +2416,7 @@ static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
goto out_default;
|
||||
error = decode_getacl3resok(xdr, result);
|
||||
error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req));
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
@@ -2405,7 +2435,7 @@ static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
|
||||
goto out;
|
||||
if (status != NFS3_OK)
|
||||
goto out_default;
|
||||
error = decode_post_op_attr(xdr, result);
|
||||
error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
|
||||
out:
|
||||
return error;
|
||||
out_default:
|
||||
|
@@ -206,6 +206,7 @@ struct nfs4_exception {
|
||||
unsigned char delay : 1,
|
||||
recovering : 1,
|
||||
retry : 1;
|
||||
bool interruptible;
|
||||
};
|
||||
|
||||
struct nfs4_state_recovery_ops {
|
||||
|
@@ -870,6 +870,7 @@ static int nfs4_set_client(struct nfs_server *server,
|
||||
.minorversion = minorversion,
|
||||
.net = net,
|
||||
.timeparms = timeparms,
|
||||
.cred = server->cred,
|
||||
};
|
||||
struct nfs_client *clp;
|
||||
|
||||
@@ -931,6 +932,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
|
||||
.minorversion = minor_version,
|
||||
.net = mds_clp->cl_net,
|
||||
.timeparms = &ds_timeout,
|
||||
.cred = mds_srv->cred,
|
||||
};
|
||||
char buf[INET6_ADDRSTRLEN + 1];
|
||||
|
||||
@@ -1107,6 +1109,8 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
|
||||
if (!server)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
server->cred = get_cred(current_cred());
|
||||
|
||||
auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
|
||||
|
||||
/* set up the general RPC client */
|
||||
@@ -1143,6 +1147,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
|
||||
parent_server = NFS_SB(data->sb);
|
||||
parent_client = parent_server->nfs_client;
|
||||
|
||||
server->cred = get_cred(parent_server->cred);
|
||||
|
||||
/* Initialise the client representation from the parent server */
|
||||
nfs_server_copy_userdata(server, parent_server);
|
||||
|
||||
|
@@ -125,7 +125,7 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
|
||||
return filemap_fdatawrite(file->f_mapping);
|
||||
|
||||
/* Flush writes to the server and return any errors */
|
||||
return vfs_fsync(file, 0);
|
||||
return nfs_wb_all(inode);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
@@ -187,7 +187,7 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
||||
bool same_inode = false;
|
||||
int ret;
|
||||
|
||||
if (remap_flags & ~REMAP_FILE_ADVISORY)
|
||||
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
||||
return -EINVAL;
|
||||
|
||||
/* check alignment w.r.t. clone_blksize */
|
||||
|
@@ -69,8 +69,16 @@ struct idmap {
|
||||
struct rpc_pipe *idmap_pipe;
|
||||
struct idmap_legacy_upcalldata *idmap_upcall_data;
|
||||
struct mutex idmap_mutex;
|
||||
const struct cred *cred;
|
||||
};
|
||||
|
||||
static struct user_namespace *idmap_userns(const struct idmap *idmap)
|
||||
{
|
||||
if (idmap && idmap->cred)
|
||||
return idmap->cred->user_ns;
|
||||
return &init_user_ns;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
|
||||
* @fattr: fully initialised struct nfs_fattr
|
||||
@@ -271,14 +279,15 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
|
||||
const char *type, struct idmap *idmap)
|
||||
{
|
||||
char *desc;
|
||||
struct key *rkey;
|
||||
struct key *rkey = ERR_PTR(-EAGAIN);
|
||||
ssize_t ret;
|
||||
|
||||
ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
rkey = request_key(&key_type_id_resolver, desc, "");
|
||||
if (!idmap->cred || idmap->cred->user_ns == &init_user_ns)
|
||||
rkey = request_key(&key_type_id_resolver, desc, "");
|
||||
if (IS_ERR(rkey)) {
|
||||
mutex_lock(&idmap->idmap_mutex);
|
||||
rkey = request_key_with_auxdata(&key_type_id_resolver_legacy,
|
||||
@@ -452,6 +461,9 @@ nfs_idmap_new(struct nfs_client *clp)
|
||||
if (idmap == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&idmap->idmap_mutex);
|
||||
idmap->cred = get_cred(clp->cl_rpcclient->cl_cred);
|
||||
|
||||
rpc_init_pipe_dir_object(&idmap->idmap_pdo,
|
||||
&nfs_idmap_pipe_dir_object_ops,
|
||||
idmap);
|
||||
@@ -462,7 +474,6 @@ nfs_idmap_new(struct nfs_client *clp)
|
||||
goto err;
|
||||
}
|
||||
idmap->idmap_pipe = pipe;
|
||||
mutex_init(&idmap->idmap_mutex);
|
||||
|
||||
error = rpc_add_pipe_dir_object(clp->cl_net,
|
||||
&clp->cl_rpcclient->cl_pipedir_objects,
|
||||
@@ -475,6 +486,7 @@ nfs_idmap_new(struct nfs_client *clp)
|
||||
err_destroy_pipe:
|
||||
rpc_destroy_pipe_data(idmap->idmap_pipe);
|
||||
err:
|
||||
put_cred(idmap->cred);
|
||||
kfree(idmap);
|
||||
return error;
|
||||
}
|
||||
@@ -491,6 +503,7 @@ nfs_idmap_delete(struct nfs_client *clp)
|
||||
&clp->cl_rpcclient->cl_pipedir_objects,
|
||||
&idmap->idmap_pdo);
|
||||
rpc_destroy_pipe_data(idmap->idmap_pipe);
|
||||
put_cred(idmap->cred);
|
||||
kfree(idmap);
|
||||
}
|
||||
|
||||
@@ -735,7 +748,7 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
|
||||
if (!nfs_map_string_to_numeric(name, namelen, &id))
|
||||
ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
|
||||
if (ret == 0) {
|
||||
*uid = make_kuid(&init_user_ns, id);
|
||||
*uid = make_kuid(idmap_userns(idmap), id);
|
||||
if (!uid_valid(*uid))
|
||||
ret = -ERANGE;
|
||||
}
|
||||
@@ -752,7 +765,7 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
|
||||
if (!nfs_map_string_to_numeric(name, namelen, &id))
|
||||
ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
|
||||
if (ret == 0) {
|
||||
*gid = make_kgid(&init_user_ns, id);
|
||||
*gid = make_kgid(idmap_userns(idmap), id);
|
||||
if (!gid_valid(*gid))
|
||||
ret = -ERANGE;
|
||||
}
|
||||
@@ -766,7 +779,7 @@ int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf,
|
||||
int ret = -EINVAL;
|
||||
__u32 id;
|
||||
|
||||
id = from_kuid(&init_user_ns, uid);
|
||||
id = from_kuid_munged(idmap_userns(idmap), uid);
|
||||
if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
|
||||
ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
|
||||
if (ret < 0)
|
||||
@@ -780,7 +793,7 @@ int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf,
|
||||
int ret = -EINVAL;
|
||||
__u32 id;
|
||||
|
||||
id = from_kgid(&init_user_ns, gid);
|
||||
id = from_kgid_munged(idmap_userns(idmap), gid);
|
||||
if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
|
||||
ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
|
||||
if (ret < 0)
|
||||
|
@@ -400,17 +400,32 @@ static long nfs4_update_delay(long *timeout)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
|
||||
static int nfs4_delay_killable(long *timeout)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
might_sleep();
|
||||
|
||||
freezable_schedule_timeout_killable_unsafe(
|
||||
nfs4_update_delay(timeout));
|
||||
if (fatal_signal_pending(current))
|
||||
res = -ERESTARTSYS;
|
||||
return res;
|
||||
if (!__fatal_signal_pending(current))
|
||||
return 0;
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
static int nfs4_delay_interruptible(long *timeout)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
freezable_schedule_timeout_interruptible(nfs4_update_delay(timeout));
|
||||
if (!signal_pending(current))
|
||||
return 0;
|
||||
return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
|
||||
}
|
||||
|
||||
static int nfs4_delay(long *timeout, bool interruptible)
|
||||
{
|
||||
if (interruptible)
|
||||
return nfs4_delay_interruptible(timeout);
|
||||
return nfs4_delay_killable(timeout);
|
||||
}
|
||||
|
||||
/* This is the error handling routine for processes that are allowed
|
||||
@@ -546,7 +561,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
ret = nfs4_delay(server->client, &exception->timeout);
|
||||
ret = nfs4_delay(&exception->timeout,
|
||||
exception->interruptible);
|
||||
goto out_retry;
|
||||
}
|
||||
if (exception->recovering) {
|
||||
@@ -978,10 +994,8 @@ int nfs4_setup_sequence(struct nfs_client *client,
|
||||
if (res->sr_slot != NULL)
|
||||
goto out_start;
|
||||
|
||||
if (session) {
|
||||
if (session)
|
||||
tbl = &session->fc_slot_table;
|
||||
task->tk_timeout = 0;
|
||||
}
|
||||
|
||||
spin_lock(&tbl->slot_tbl_lock);
|
||||
/* The state manager will wait until the slot table is empty */
|
||||
@@ -990,9 +1004,8 @@ int nfs4_setup_sequence(struct nfs_client *client,
|
||||
|
||||
slot = nfs4_alloc_slot(tbl);
|
||||
if (IS_ERR(slot)) {
|
||||
/* Try again in 1/4 second */
|
||||
if (slot == ERR_PTR(-ENOMEM))
|
||||
task->tk_timeout = HZ >> 2;
|
||||
goto out_sleep_timeout;
|
||||
goto out_sleep;
|
||||
}
|
||||
spin_unlock(&tbl->slot_tbl_lock);
|
||||
@@ -1004,11 +1017,20 @@ out_start:
|
||||
nfs41_sequence_res_init(res);
|
||||
rpc_call_start(task);
|
||||
return 0;
|
||||
|
||||
out_sleep_timeout:
|
||||
/* Try again in 1/4 second */
|
||||
if (args->sa_privileged)
|
||||
rpc_sleep_on_priority_timeout(&tbl->slot_tbl_waitq, task,
|
||||
jiffies + (HZ >> 2), RPC_PRIORITY_PRIVILEGED);
|
||||
else
|
||||
rpc_sleep_on_timeout(&tbl->slot_tbl_waitq, task,
|
||||
NULL, jiffies + (HZ >> 2));
|
||||
spin_unlock(&tbl->slot_tbl_lock);
|
||||
return -EAGAIN;
|
||||
out_sleep:
|
||||
if (args->sa_privileged)
|
||||
rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
|
||||
NULL, RPC_PRIORITY_PRIVILEGED);
|
||||
RPC_PRIORITY_PRIVILEGED);
|
||||
else
|
||||
rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
|
||||
spin_unlock(&tbl->slot_tbl_lock);
|
||||
@@ -3060,7 +3082,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
|
||||
int *opened)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct nfs4_state *res;
|
||||
struct nfs4_open_createattrs c = {
|
||||
.label = label,
|
||||
@@ -3673,7 +3697,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
||||
|
||||
int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(server,
|
||||
@@ -3715,7 +3741,9 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fsinfo *info)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_lookup_root(server, fhandle, info);
|
||||
@@ -3942,7 +3970,9 @@ static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_getattr(server, fhandle, fattr, label, inode);
|
||||
@@ -4065,7 +4095,9 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
|
||||
const struct qstr *name, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct rpc_clnt *client = *clnt;
|
||||
int err;
|
||||
do {
|
||||
@@ -4169,7 +4201,9 @@ static int _nfs4_proc_lookupp(struct inode *inode,
|
||||
static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
|
||||
@@ -4216,7 +4250,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
|
||||
|
||||
static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_access(inode, entry);
|
||||
@@ -4271,7 +4307,9 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
|
||||
static int nfs4_proc_readlink(struct inode *inode, struct page *page,
|
||||
unsigned int pgbase, unsigned int pglen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
|
||||
@@ -4347,7 +4385,9 @@ _nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
|
||||
|
||||
static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int err;
|
||||
|
||||
@@ -4368,7 +4408,9 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
do {
|
||||
@@ -4527,7 +4569,9 @@ out:
|
||||
|
||||
static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(NFS_SERVER(inode),
|
||||
@@ -4634,7 +4678,9 @@ out:
|
||||
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page, unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct nfs4_label l, *label = NULL;
|
||||
int err;
|
||||
|
||||
@@ -4673,7 +4719,9 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
struct iattr *sattr)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct nfs4_label l, *label = NULL;
|
||||
int err;
|
||||
|
||||
@@ -4733,7 +4781,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
|
||||
static int nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
|
||||
u64 cookie, struct page **pages, unsigned int count, bool plus)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_readdir(dentry, cred, cookie,
|
||||
@@ -4784,7 +4834,9 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
|
||||
struct iattr *sattr, dev_t rdev)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
struct nfs4_label l, *label = NULL;
|
||||
int err;
|
||||
|
||||
@@ -4826,7 +4878,9 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(server,
|
||||
@@ -4857,7 +4911,9 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
unsigned long now = jiffies;
|
||||
int err;
|
||||
|
||||
@@ -4919,7 +4975,9 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
|
||||
static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_pathconf *pathconf)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
do {
|
||||
@@ -5488,7 +5546,9 @@ out_free:
|
||||
|
||||
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = __nfs4_get_acl_uncached(inode, buf, buflen);
|
||||
@@ -5622,7 +5682,9 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,
|
||||
static int nfs4_get_security_label(struct inode *inode, void *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
|
||||
@@ -6263,7 +6325,9 @@ out:
|
||||
|
||||
static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
do {
|
||||
@@ -6827,6 +6891,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
|
||||
struct nfs4_exception exception = {
|
||||
.state = state,
|
||||
.inode = state->inode,
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
|
||||
@@ -7240,7 +7305,9 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
|
||||
struct nfs4_fs_locations *fs_locations,
|
||||
struct page *page)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs4_proc_fs_locations(client, dir, name,
|
||||
@@ -7383,7 +7450,9 @@ int nfs4_proc_get_locations(struct inode *inode,
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
const struct nfs4_mig_recovery_ops *ops =
|
||||
clp->cl_mvops->mig_recovery_ops;
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int status;
|
||||
|
||||
dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
|
||||
@@ -7507,7 +7576,9 @@ int nfs4_proc_fsid_present(struct inode *inode, const struct cred *cred)
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
const struct nfs4_mig_recovery_ops *ops =
|
||||
clp->cl_mvops->mig_recovery_ops;
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int status;
|
||||
|
||||
dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
|
||||
@@ -7573,7 +7644,9 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
|
||||
int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
|
||||
struct nfs4_secinfo_flavors *flavors)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = -NFS4ERR_WRONGSEC;
|
||||
@@ -9263,7 +9336,9 @@ static int
|
||||
nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
/* first try using integrity protection */
|
||||
@@ -9430,7 +9505,9 @@ static int nfs41_test_stateid(struct nfs_server *server,
|
||||
nfs4_stateid *stateid,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
};
|
||||
int err;
|
||||
do {
|
||||
err = _nfs41_test_stateid(server, stateid, cred);
|
||||
|
@@ -159,6 +159,10 @@ int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
/* Sustain the lease, even if it's empty. If the clientid4
|
||||
* goes stale it's of no use for trunking discovery. */
|
||||
nfs4_schedule_state_renewal(*result);
|
||||
|
||||
/* If the client state need to recover, do it. */
|
||||
if (clp->cl_state)
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
@@ -2346,8 +2350,7 @@ static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
|
||||
{
|
||||
/* FIXME: For now, we destroy all layouts. */
|
||||
pnfs_destroy_all_layouts(clp);
|
||||
/* FIXME: For now, we test all delegations+open state+locks. */
|
||||
nfs41_handle_some_state_revoked(clp);
|
||||
nfs_test_expired_all_delegations(clp);
|
||||
dprintk("%s: Recallable state revoked on server %s!\n", __func__,
|
||||
clp->cl_hostname);
|
||||
}
|
||||
|
@@ -16,8 +16,8 @@
|
||||
#include <linux/nfs.h>
|
||||
#include <linux/nfs3.h>
|
||||
#include <linux/nfs4.h>
|
||||
#include <linux/nfs_page.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_page.h>
|
||||
#include <linux/nfs_mount.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
@@ -47,7 +47,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
|
||||
|
||||
hdr->req = nfs_list_entry(mirror->pg_list.next);
|
||||
hdr->inode = desc->pg_inode;
|
||||
hdr->cred = hdr->req->wb_context->cred;
|
||||
hdr->cred = nfs_req_openctx(hdr->req)->cred;
|
||||
hdr->io_start = req_offset(hdr->req);
|
||||
hdr->good_bytes = mirror->pg_count;
|
||||
hdr->io_completion = desc->pg_io_completion;
|
||||
@@ -295,25 +295,13 @@ out:
|
||||
nfs_release_request(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_create_request - Create an NFS read/write request.
|
||||
* @ctx: open context to use
|
||||
* @page: page to write
|
||||
* @last: last nfs request created for this page group or NULL if head
|
||||
* @offset: starting offset within the page for the write
|
||||
* @count: number of bytes to read/write
|
||||
*
|
||||
* The page must be locked by the caller. This makes sure we never
|
||||
* create two different requests for the same page.
|
||||
* User should ensure it is safe to sleep in this function.
|
||||
*/
|
||||
struct nfs_page *
|
||||
nfs_create_request(struct nfs_open_context *ctx, struct page *page,
|
||||
struct nfs_page *last, unsigned int offset,
|
||||
static struct nfs_page *
|
||||
__nfs_create_request(struct nfs_lock_context *l_ctx, struct page *page,
|
||||
unsigned int pgbase, unsigned int offset,
|
||||
unsigned int count)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
struct nfs_lock_context *l_ctx;
|
||||
struct nfs_open_context *ctx = l_ctx->open_context;
|
||||
|
||||
if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))
|
||||
return ERR_PTR(-EBADF);
|
||||
@@ -322,13 +310,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
|
||||
if (req == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* get lock context early so we can deal with alloc failures */
|
||||
l_ctx = nfs_get_lock_context(ctx);
|
||||
if (IS_ERR(l_ctx)) {
|
||||
nfs_page_free(req);
|
||||
return ERR_CAST(l_ctx);
|
||||
}
|
||||
req->wb_lock_context = l_ctx;
|
||||
refcount_inc(&l_ctx->count);
|
||||
atomic_inc(&l_ctx->io_count);
|
||||
|
||||
/* Initialize the request struct. Initially, we assume a
|
||||
@@ -340,14 +323,58 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
|
||||
get_page(page);
|
||||
}
|
||||
req->wb_offset = offset;
|
||||
req->wb_pgbase = offset;
|
||||
req->wb_pgbase = pgbase;
|
||||
req->wb_bytes = count;
|
||||
req->wb_context = get_nfs_open_context(ctx);
|
||||
kref_init(&req->wb_kref);
|
||||
nfs_page_group_init(req, last);
|
||||
req->wb_nio = 0;
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_create_request - Create an NFS read/write request.
|
||||
* @ctx: open context to use
|
||||
* @page: page to write
|
||||
* @offset: starting offset within the page for the write
|
||||
* @count: number of bytes to read/write
|
||||
*
|
||||
* The page must be locked by the caller. This makes sure we never
|
||||
* create two different requests for the same page.
|
||||
* User should ensure it is safe to sleep in this function.
|
||||
*/
|
||||
struct nfs_page *
|
||||
nfs_create_request(struct nfs_open_context *ctx, struct page *page,
|
||||
unsigned int offset, unsigned int count)
|
||||
{
|
||||
struct nfs_lock_context *l_ctx = nfs_get_lock_context(ctx);
|
||||
struct nfs_page *ret;
|
||||
|
||||
if (IS_ERR(l_ctx))
|
||||
return ERR_CAST(l_ctx);
|
||||
ret = __nfs_create_request(l_ctx, page, offset, offset, count);
|
||||
if (!IS_ERR(ret))
|
||||
nfs_page_group_init(ret, NULL);
|
||||
nfs_put_lock_context(l_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nfs_page *
|
||||
nfs_create_subreq(struct nfs_page *req, struct nfs_page *last,
|
||||
unsigned int pgbase, unsigned int offset,
|
||||
unsigned int count)
|
||||
{
|
||||
struct nfs_page *ret;
|
||||
|
||||
ret = __nfs_create_request(req->wb_lock_context, req->wb_page,
|
||||
pgbase, offset, count);
|
||||
if (!IS_ERR(ret)) {
|
||||
nfs_lock_request(ret);
|
||||
ret->wb_index = req->wb_index;
|
||||
nfs_page_group_init(ret, last);
|
||||
ret->wb_nio = req->wb_nio;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_unlock_request - Unlock request and wake up sleepers.
|
||||
* @req: pointer to request
|
||||
@@ -386,8 +413,8 @@ void nfs_unlock_and_release_request(struct nfs_page *req)
|
||||
static void nfs_clear_request(struct nfs_page *req)
|
||||
{
|
||||
struct page *page = req->wb_page;
|
||||
struct nfs_open_context *ctx = req->wb_context;
|
||||
struct nfs_lock_context *l_ctx = req->wb_lock_context;
|
||||
struct nfs_open_context *ctx;
|
||||
|
||||
if (page != NULL) {
|
||||
put_page(page);
|
||||
@@ -396,16 +423,13 @@ static void nfs_clear_request(struct nfs_page *req)
|
||||
if (l_ctx != NULL) {
|
||||
if (atomic_dec_and_test(&l_ctx->io_count)) {
|
||||
wake_up_var(&l_ctx->io_count);
|
||||
ctx = l_ctx->open_context;
|
||||
if (test_bit(NFS_CONTEXT_UNLOCK, &ctx->flags))
|
||||
rpc_wake_up(&NFS_SERVER(d_inode(ctx->dentry))->uoc_rpcwaitq);
|
||||
}
|
||||
nfs_put_lock_context(l_ctx);
|
||||
req->wb_lock_context = NULL;
|
||||
}
|
||||
if (ctx != NULL) {
|
||||
put_nfs_open_context(ctx);
|
||||
req->wb_context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,7 +574,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
|
||||
hdr->args.pgbase = req->wb_pgbase;
|
||||
hdr->args.pages = hdr->page_array.pagevec;
|
||||
hdr->args.count = count;
|
||||
hdr->args.context = get_nfs_open_context(req->wb_context);
|
||||
hdr->args.context = get_nfs_open_context(nfs_req_openctx(req));
|
||||
hdr->args.lock_context = req->wb_lock_context;
|
||||
hdr->args.stable = NFS_UNSTABLE;
|
||||
switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
|
||||
@@ -698,6 +722,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
|
||||
desc->pg_mirrors_dynamic = NULL;
|
||||
desc->pg_mirrors = desc->pg_mirrors_static;
|
||||
nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize);
|
||||
desc->pg_maxretrans = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,9 +931,9 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
|
||||
struct file_lock_context *flctx;
|
||||
|
||||
if (prev) {
|
||||
if (!nfs_match_open_context(req->wb_context, prev->wb_context))
|
||||
if (!nfs_match_open_context(nfs_req_openctx(req), nfs_req_openctx(prev)))
|
||||
return false;
|
||||
flctx = d_inode(req->wb_context->dentry)->i_flctx;
|
||||
flctx = d_inode(nfs_req_openctx(req)->dentry)->i_flctx;
|
||||
if (flctx != NULL &&
|
||||
!(list_empty_careful(&flctx->flc_posix) &&
|
||||
list_empty_careful(&flctx->flc_flock)) &&
|
||||
@@ -957,6 +982,15 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
|
||||
return 0;
|
||||
mirror->pg_base = req->wb_pgbase;
|
||||
}
|
||||
|
||||
if (desc->pg_maxretrans && req->wb_nio > desc->pg_maxretrans) {
|
||||
if (NFS_SERVER(desc->pg_inode)->flags & NFS_MOUNT_SOFTERR)
|
||||
desc->pg_error = -ETIMEDOUT;
|
||||
else
|
||||
desc->pg_error = -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!nfs_can_coalesce_requests(prev, req, desc))
|
||||
return 0;
|
||||
nfs_list_move_request(req, &mirror->pg_list);
|
||||
@@ -1049,14 +1083,10 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
|
||||
pgbase += subreq->wb_bytes;
|
||||
|
||||
if (bytes_left) {
|
||||
subreq = nfs_create_request(req->wb_context,
|
||||
req->wb_page,
|
||||
subreq, pgbase, bytes_left);
|
||||
subreq = nfs_create_subreq(req, subreq, pgbase,
|
||||
offset, bytes_left);
|
||||
if (IS_ERR(subreq))
|
||||
goto err_ptr;
|
||||
nfs_lock_request(subreq);
|
||||
subreq->wb_offset = offset;
|
||||
subreq->wb_index = req->wb_index;
|
||||
}
|
||||
} while (bytes_left > 0);
|
||||
|
||||
@@ -1158,19 +1188,14 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
|
||||
lastreq = lastreq->wb_this_page)
|
||||
;
|
||||
|
||||
dupreq = nfs_create_request(req->wb_context,
|
||||
req->wb_page, lastreq, pgbase, bytes);
|
||||
dupreq = nfs_create_subreq(req, lastreq,
|
||||
pgbase, offset, bytes);
|
||||
|
||||
nfs_page_group_unlock(req);
|
||||
if (IS_ERR(dupreq)) {
|
||||
nfs_page_group_unlock(req);
|
||||
desc->pg_error = PTR_ERR(dupreq);
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
nfs_lock_request(dupreq);
|
||||
nfs_page_group_unlock(req);
|
||||
dupreq->wb_offset = offset;
|
||||
dupreq->wb_index = req->wb_index;
|
||||
} else
|
||||
dupreq = req;
|
||||
|
||||
|
@@ -2436,7 +2436,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
|
||||
rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
|
||||
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
req_offset(req),
|
||||
rd_size,
|
||||
IOMODE_READ,
|
||||
@@ -2463,7 +2463,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
|
||||
pnfs_generic_pg_check_range(pgio, req);
|
||||
if (pgio->pg_lseg == NULL) {
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
nfs_req_openctx(req),
|
||||
req_offset(req),
|
||||
wb_size,
|
||||
IOMODE_RW,
|
||||
|
@@ -459,7 +459,7 @@ static inline bool
|
||||
pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
|
||||
struct nfs_commit_info *cinfo, u32 ds_commit_idx)
|
||||
{
|
||||
struct inode *inode = d_inode(req->wb_context->dentry);
|
||||
struct inode *inode = d_inode(nfs_req_openctx(req)->dentry);
|
||||
struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
|
||||
|
||||
if (lseg == NULL || ld->mark_request_commit == NULL)
|
||||
@@ -471,7 +471,7 @@ pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
|
||||
static inline bool
|
||||
pnfs_clear_request_commit(struct nfs_page *req, struct nfs_commit_info *cinfo)
|
||||
{
|
||||
struct inode *inode = d_inode(req->wb_context->dentry);
|
||||
struct inode *inode = d_inode(nfs_req_openctx(req)->dentry);
|
||||
struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
|
||||
|
||||
if (ld == NULL || ld->clear_request_commit == NULL)
|
||||
|
@@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
|
||||
|
||||
static void nfs_readpage_release(struct nfs_page *req)
|
||||
{
|
||||
struct inode *inode = d_inode(req->wb_context->dentry);
|
||||
struct inode *inode = d_inode(nfs_req_openctx(req)->dentry);
|
||||
|
||||
dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id,
|
||||
(unsigned long long)NFS_FILEID(inode), req->wb_bytes,
|
||||
@@ -118,7 +118,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
|
||||
len = nfs_page_length(page);
|
||||
if (len == 0)
|
||||
return nfs_return_empty_page(page);
|
||||
new = nfs_create_request(ctx, page, NULL, 0, len);
|
||||
new = nfs_create_request(ctx, page, 0, len);
|
||||
if (IS_ERR(new)) {
|
||||
unlock_page(page);
|
||||
return PTR_ERR(new);
|
||||
@@ -363,7 +363,7 @@ readpage_async_filler(void *data, struct page *page)
|
||||
if (len == 0)
|
||||
return nfs_return_empty_page(page);
|
||||
|
||||
new = nfs_create_request(desc->ctx, page, NULL, 0, len);
|
||||
new = nfs_create_request(desc->ctx, page, 0, len);
|
||||
if (IS_ERR(new))
|
||||
goto out_error;
|
||||
|
||||
|
@@ -78,7 +78,7 @@
|
||||
|
||||
enum {
|
||||
/* Mount options that take no arguments */
|
||||
Opt_soft, Opt_hard,
|
||||
Opt_soft, Opt_softerr, Opt_hard,
|
||||
Opt_posix, Opt_noposix,
|
||||
Opt_cto, Opt_nocto,
|
||||
Opt_ac, Opt_noac,
|
||||
@@ -125,6 +125,7 @@ static const match_table_t nfs_mount_option_tokens = {
|
||||
{ Opt_sloppy, "sloppy" },
|
||||
|
||||
{ Opt_soft, "soft" },
|
||||
{ Opt_softerr, "softerr" },
|
||||
{ Opt_hard, "hard" },
|
||||
{ Opt_deprecated, "intr" },
|
||||
{ Opt_deprecated, "nointr" },
|
||||
@@ -628,7 +629,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
const char *str;
|
||||
const char *nostr;
|
||||
} nfs_info[] = {
|
||||
{ NFS_MOUNT_SOFT, ",soft", ",hard" },
|
||||
{ NFS_MOUNT_SOFT, ",soft", "" },
|
||||
{ NFS_MOUNT_SOFTERR, ",softerr", "" },
|
||||
{ NFS_MOUNT_POSIX, ",posix", "" },
|
||||
{ NFS_MOUNT_NOCTO, ",nocto", "" },
|
||||
{ NFS_MOUNT_NOAC, ",noac", "" },
|
||||
@@ -658,6 +660,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
|
||||
if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults)
|
||||
seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
|
||||
if (!(nfss->flags & (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR)))
|
||||
seq_puts(m, ",hard");
|
||||
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
|
||||
if (nfss->flags & nfs_infop->flag)
|
||||
seq_puts(m, nfs_infop->str);
|
||||
@@ -1239,9 +1243,14 @@ static int nfs_parse_mount_options(char *raw,
|
||||
*/
|
||||
case Opt_soft:
|
||||
mnt->flags |= NFS_MOUNT_SOFT;
|
||||
mnt->flags &= ~NFS_MOUNT_SOFTERR;
|
||||
break;
|
||||
case Opt_softerr:
|
||||
mnt->flags |= NFS_MOUNT_SOFTERR;
|
||||
mnt->flags &= ~NFS_MOUNT_SOFT;
|
||||
break;
|
||||
case Opt_hard:
|
||||
mnt->flags &= ~NFS_MOUNT_SOFT;
|
||||
mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
|
||||
break;
|
||||
case Opt_posix:
|
||||
mnt->flags |= NFS_MOUNT_POSIX;
|
||||
@@ -2476,6 +2485,21 @@ static int nfs_compare_super_address(struct nfs_server *server1,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nfs_compare_userns(const struct nfs_server *old,
|
||||
const struct nfs_server *new)
|
||||
{
|
||||
const struct user_namespace *oldns = &init_user_ns;
|
||||
const struct user_namespace *newns = &init_user_ns;
|
||||
|
||||
if (old->client && old->client->cl_cred)
|
||||
oldns = old->client->cl_cred->user_ns;
|
||||
if (new->client && new->client->cl_cred)
|
||||
newns = new->client->cl_cred->user_ns;
|
||||
if (oldns != newns)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nfs_compare_super(struct super_block *sb, void *data)
|
||||
{
|
||||
struct nfs_sb_mountdata *sb_mntdata = data;
|
||||
@@ -2489,6 +2513,8 @@ static int nfs_compare_super(struct super_block *sb, void *data)
|
||||
return 0;
|
||||
if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
|
||||
return 0;
|
||||
if (!nfs_compare_userns(old, server))
|
||||
return 0;
|
||||
return nfs_compare_mount_options(sb, server, mntflags);
|
||||
}
|
||||
|
||||
|
@@ -26,8 +26,9 @@
|
||||
* and straight-forward than readdir caching.
|
||||
*/
|
||||
|
||||
static int nfs_symlink_filler(struct inode *inode, struct page *page)
|
||||
static int nfs_symlink_filler(void *data, struct page *page)
|
||||
{
|
||||
struct inode *inode = data;
|
||||
int error;
|
||||
|
||||
error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE);
|
||||
@@ -65,8 +66,8 @@ static const char *nfs_get_link(struct dentry *dentry,
|
||||
err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
|
||||
if (err)
|
||||
return err;
|
||||
page = read_cache_page(&inode->i_data, 0,
|
||||
(filler_t *)nfs_symlink_filler, inode);
|
||||
page = read_cache_page(&inode->i_data, 0, nfs_symlink_filler,
|
||||
inode);
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
}
|
||||
|
@@ -244,6 +244,12 @@ static void nfs_set_pageerror(struct address_space *mapping)
|
||||
nfs_zap_mapping(mapping->host, mapping);
|
||||
}
|
||||
|
||||
static void nfs_mapping_set_error(struct page *page, int error)
|
||||
{
|
||||
SetPageError(page);
|
||||
mapping_set_error(page_file_mapping(page), error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_page_group_search_locked
|
||||
* @head - head request of page group
|
||||
@@ -582,11 +588,10 @@ release_request:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void nfs_write_error_remove_page(struct nfs_page *req)
|
||||
static void nfs_write_error(struct nfs_page *req, int error)
|
||||
{
|
||||
nfs_mapping_set_error(req->wb_page, error);
|
||||
nfs_end_page_writeback(req);
|
||||
generic_error_remove_page(page_file_mapping(req->wb_page),
|
||||
req->wb_page);
|
||||
nfs_release_request(req);
|
||||
}
|
||||
|
||||
@@ -609,6 +614,7 @@ nfs_error_is_fatal_on_server(int err)
|
||||
static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
|
||||
struct page *page)
|
||||
{
|
||||
struct address_space *mapping;
|
||||
struct nfs_page *req;
|
||||
int ret = 0;
|
||||
|
||||
@@ -622,19 +628,19 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
|
||||
nfs_set_page_writeback(page);
|
||||
WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags));
|
||||
|
||||
ret = req->wb_context->error;
|
||||
/* If there is a fatal error that covers this write, just exit */
|
||||
if (nfs_error_is_fatal_on_server(ret))
|
||||
ret = 0;
|
||||
mapping = page_file_mapping(page);
|
||||
if (test_bit(AS_ENOSPC, &mapping->flags) ||
|
||||
test_bit(AS_EIO, &mapping->flags))
|
||||
goto out_launder;
|
||||
|
||||
ret = 0;
|
||||
if (!nfs_pageio_add_request(pgio, req)) {
|
||||
ret = pgio->pg_error;
|
||||
/*
|
||||
* Remove the problematic req upon fatal errors on the server
|
||||
*/
|
||||
if (nfs_error_is_fatal(ret)) {
|
||||
nfs_context_set_write_error(req->wb_context, ret);
|
||||
if (nfs_error_is_fatal_on_server(ret))
|
||||
goto out_launder;
|
||||
} else
|
||||
@@ -646,8 +652,8 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
|
||||
out:
|
||||
return ret;
|
||||
out_launder:
|
||||
nfs_write_error_remove_page(req);
|
||||
return ret;
|
||||
nfs_write_error(req, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs_do_writepage(struct page *page, struct writeback_control *wbc,
|
||||
@@ -958,7 +964,8 @@ static void
|
||||
nfs_clear_request_commit(struct nfs_page *req)
|
||||
{
|
||||
if (test_bit(PG_CLEAN, &req->wb_flags)) {
|
||||
struct inode *inode = d_inode(req->wb_context->dentry);
|
||||
struct nfs_open_context *ctx = nfs_req_openctx(req);
|
||||
struct inode *inode = d_inode(ctx->dentry);
|
||||
struct nfs_commit_info cinfo;
|
||||
|
||||
nfs_init_cinfo_from_inode(&cinfo, inode);
|
||||
@@ -999,10 +1006,12 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
|
||||
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) &&
|
||||
(hdr->good_bytes < bytes)) {
|
||||
nfs_set_pageerror(page_file_mapping(req->wb_page));
|
||||
nfs_context_set_write_error(req->wb_context, hdr->error);
|
||||
nfs_mapping_set_error(req->wb_page, hdr->error);
|
||||
goto remove_req;
|
||||
}
|
||||
if (nfs_write_need_commit(hdr)) {
|
||||
/* Reset wb_nio, since the write was successful. */
|
||||
req->wb_nio = 0;
|
||||
memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf));
|
||||
nfs_mark_request_commit(req, hdr->lseg, &cinfo,
|
||||
hdr->pgio_mirror_idx);
|
||||
@@ -1136,6 +1145,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
|
||||
req->wb_bytes = end - req->wb_offset;
|
||||
else
|
||||
req->wb_bytes = rqend - req->wb_offset;
|
||||
req->wb_nio = 0;
|
||||
return req;
|
||||
out_flushme:
|
||||
/*
|
||||
@@ -1165,7 +1175,7 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
|
||||
req = nfs_try_to_update_request(inode, page, offset, bytes);
|
||||
if (req != NULL)
|
||||
goto out;
|
||||
req = nfs_create_request(ctx, page, NULL, offset, bytes);
|
||||
req = nfs_create_request(ctx, page, offset, bytes);
|
||||
if (IS_ERR(req))
|
||||
goto out;
|
||||
nfs_inode_add_request(inode, req);
|
||||
@@ -1210,7 +1220,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
|
||||
return 0;
|
||||
l_ctx = req->wb_lock_context;
|
||||
do_flush = req->wb_page != page ||
|
||||
!nfs_match_open_context(req->wb_context, ctx);
|
||||
!nfs_match_open_context(nfs_req_openctx(req), ctx);
|
||||
if (l_ctx && flctx &&
|
||||
!(list_empty_careful(&flctx->flc_posix) &&
|
||||
list_empty_careful(&flctx->flc_flock))) {
|
||||
@@ -1410,8 +1420,10 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr,
|
||||
*/
|
||||
static void nfs_redirty_request(struct nfs_page *req)
|
||||
{
|
||||
/* Bump the transmission count */
|
||||
req->wb_nio++;
|
||||
nfs_mark_request_dirty(req);
|
||||
set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
|
||||
set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
|
||||
nfs_end_page_writeback(req);
|
||||
nfs_release_request(req);
|
||||
}
|
||||
@@ -1423,14 +1435,10 @@ static void nfs_async_write_error(struct list_head *head, int error)
|
||||
while (!list_empty(head)) {
|
||||
req = nfs_list_entry(head->next);
|
||||
nfs_list_remove_request(req);
|
||||
if (nfs_error_is_fatal(error)) {
|
||||
nfs_context_set_write_error(req->wb_context, error);
|
||||
if (nfs_error_is_fatal_on_server(error)) {
|
||||
nfs_write_error_remove_page(req);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nfs_redirty_request(req);
|
||||
if (nfs_error_is_fatal(error))
|
||||
nfs_write_error(req, error);
|
||||
else
|
||||
nfs_redirty_request(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1735,7 +1743,8 @@ void nfs_init_commit(struct nfs_commit_data *data,
|
||||
struct nfs_commit_info *cinfo)
|
||||
{
|
||||
struct nfs_page *first = nfs_list_entry(head->next);
|
||||
struct inode *inode = d_inode(first->wb_context->dentry);
|
||||
struct nfs_open_context *ctx = nfs_req_openctx(first);
|
||||
struct inode *inode = d_inode(ctx->dentry);
|
||||
|
||||
/* Set up the RPC argument and reply structs
|
||||
* NB: take care not to mess about with data->commit et al. */
|
||||
@@ -1743,7 +1752,7 @@ void nfs_init_commit(struct nfs_commit_data *data,
|
||||
list_splice_init(head, &data->pages);
|
||||
|
||||
data->inode = inode;
|
||||
data->cred = first->wb_context->cred;
|
||||
data->cred = ctx->cred;
|
||||
data->lseg = lseg; /* reference transferred */
|
||||
/* only set lwb for pnfs commit */
|
||||
if (lseg)
|
||||
@@ -1756,7 +1765,7 @@ void nfs_init_commit(struct nfs_commit_data *data,
|
||||
/* Note: we always request a commit of the entire inode */
|
||||
data->args.offset = 0;
|
||||
data->args.count = 0;
|
||||
data->context = get_nfs_open_context(first->wb_context);
|
||||
data->context = get_nfs_open_context(ctx);
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.verf = &data->verf;
|
||||
nfs_fattr_init(&data->fattr);
|
||||
@@ -1839,14 +1848,15 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
|
||||
nfs_clear_page_commit(req->wb_page);
|
||||
|
||||
dprintk("NFS: commit (%s/%llu %d@%lld)",
|
||||
req->wb_context->dentry->d_sb->s_id,
|
||||
(unsigned long long)NFS_FILEID(d_inode(req->wb_context->dentry)),
|
||||
nfs_req_openctx(req)->dentry->d_sb->s_id,
|
||||
(unsigned long long)NFS_FILEID(d_inode(nfs_req_openctx(req)->dentry)),
|
||||
req->wb_bytes,
|
||||
(long long)req_offset(req));
|
||||
if (status < 0) {
|
||||
nfs_context_set_write_error(req->wb_context, status);
|
||||
if (req->wb_page)
|
||||
if (req->wb_page) {
|
||||
nfs_mapping_set_error(req->wb_page, status);
|
||||
nfs_inode_remove_request(req);
|
||||
}
|
||||
dprintk_cont(", error = %d\n", status);
|
||||
goto next;
|
||||
}
|
||||
@@ -1863,7 +1873,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
|
||||
/* We have a mismatch. Write the page again */
|
||||
dprintk_cont(" mismatch\n");
|
||||
nfs_mark_request_dirty(req);
|
||||
set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
|
||||
set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
|
||||
next:
|
||||
nfs_unlock_and_release_request(req);
|
||||
/* Latency breaker */
|
||||
|
Reference in New Issue
Block a user