mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
NFS client updates for Linux 4.19
Stable bufixes:
- v3.17+: Fix an off-by-one in bl_map_stripe()
- v4.9+: NFSv4 client live hangs after live data migration recovery
- v4.18+: xprtrdma: Fix disconnect regression
- v4.14+: Fix locking in pnfs_generic_recover_commit_reqs
- v4.9+: Fix a sleep in atomic context in nfs4_callback_sequence()
Features:
- Add support for asynchronous server-side COPY operations
Other bugfixes and cleanups:
- Optitmizations and fixes involving NFS v4.1 / pNFS layout handling
- Optimize lseek(fd, SEEK_CUR, 0) on directories to avoid locking
- Immediately reschedule writeback when the server replies with an error
- Fix excessive attribute revalidation in nfs_execute_ok()
- Add error checking to nfs_idmap_prepare_message()
- Use new vm_fault_t return type
- Return a delegation when reclaiming one that the server has recalled
- Referrals should inherit proto setting from parents
- Make rpc_auth_create_args a const
- Improvements to rpc_iostats tracking
- Fix a potential reference leak when there is an error processing a callback
- Fix rmdir / mkdir / rename nlink accounting
- Fix updating inode change attribute
- Fix error handling in nfsn4_sp4_select_mode()
- Use an appropriate work queue for direct-write completion
- Don't busy wait if NFSv4 session draining is interrupted
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEnZ5MQTpR7cLU7KEp18tUv7ClQOsFAlt/CYIACgkQ18tUv7Cl
QOu8gBAA0xQWmgRoG6oIdYUxvgYqhuJmMqC4SU1E6mCJ93xEuUSvEFw51X+84KCt
r6UPkp/bKiVe3EIinKTplIzuxgggXNG0EQmO46FYNTl7nqpN85ffLsQoWsiD23fp
j8afqKPFR2zfhHXLKQC7k1oiOpwGqJ+EJWgIW4llE80pSNaErEoEaDqSPds5thMN
dHEjjLr8ef6cbBux6sSPjwWGNbE82uoSu3MDuV2+e62hpGkgvuEYo1vyE6ujeZW5
MUsmw+AHZkwro0msTtNBOHcPZAS0q/2UMPzl1tsDeCWNl2mugqZ6szQLSS2AThKq
Zr6iK9Q5dWjJfrQHcjRMnYJB+SCX1SfPA7ASuU34opwcWPjecbS9Q92BNTByQYwN
o9ngs2K0mZfqpYESMAmf7Il134cCBrtEp3skGko2KopJcYcE5YUFhdKihi1yQQjU
UbOOubMpQk8vY9DpDCAwGbICKwUZwGvq27uuUWL20kFVDb1+jvfHwcV4KjRAJo/E
J9aFtU+qOh4rMPMnYlEVZcAZBGfenlv/DmBl1upRpjzBkteUpUJsAbCmGyAk4616
3RECasehgsjNCQpFIhv3FpUkWzP5jt0T3gRr1NeY6WKJZwYnHEJr9PtapS+EIsCT
tB5DvvaJqFtuHFOxzn+KlGaxdSodHF7klOq7NM3AC0cX8AkWqaU=
=8+9t
-----END PGP SIGNATURE-----
Merge tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker:
"These patches include adding async support for the v4.2 COPY
operation. I think Bruce is planning to send the server patches for
the next release, but I figured we could get the client side out of
the way now since it's been in my tree for a while. This shouldn't
cause any problems, since the server will still respond with
synchronous copies even if the client requests async.
Features:
- Add support for asynchronous server-side COPY operations
Stable bufixes:
- Fix an off-by-one in bl_map_stripe() (v3.17+)
- NFSv4 client live hangs after live data migration recovery (v4.9+)
- xprtrdma: Fix disconnect regression (v4.18+)
- Fix locking in pnfs_generic_recover_commit_reqs (v4.14+)
- Fix a sleep in atomic context in nfs4_callback_sequence() (v4.9+)
Other bugfixes and cleanups:
- Optimizations and fixes involving NFS v4.1 / pNFS layout handling
- Optimize lseek(fd, SEEK_CUR, 0) on directories to avoid locking
- Immediately reschedule writeback when the server replies with an
error
- Fix excessive attribute revalidation in nfs_execute_ok()
- Add error checking to nfs_idmap_prepare_message()
- Use new vm_fault_t return type
- Return a delegation when reclaiming one that the server has
recalled
- Referrals should inherit proto setting from parents
- Make rpc_auth_create_args a const
- Improvements to rpc_iostats tracking
- Fix a potential reference leak when there is an error processing a
callback
- Fix rmdir / mkdir / rename nlink accounting
- Fix updating inode change attribute
- Fix error handling in nfsn4_sp4_select_mode()
- Use an appropriate work queue for direct-write completion
- Don't busy wait if NFSv4 session draining is interrupted"
* tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (54 commits)
pNFS: Remove unwanted optimisation of layoutget
pNFS/flexfiles: ff_layout_pg_init_read should exit on error
pNFS: Treat RECALLCONFLICT like DELAY...
pNFS: When updating the stateid in layoutreturn, also update the recall range
NFSv4: Fix a sleep in atomic context in nfs4_callback_sequence()
NFSv4: Fix locking in pnfs_generic_recover_commit_reqs
NFSv4: Fix a typo in nfs4_init_channel_attrs()
NFSv4: Don't busy wait if NFSv4 session draining is interrupted
NFS recover from destination server reboot for copies
NFS add a simple sync nfs4_proc_commit after async COPY
NFS handle COPY ERR_OFFLOAD_NO_REQS
NFS send OFFLOAD_CANCEL when COPY killed
NFS export nfs4_async_handle_error
NFS handle COPY reply CB_OFFLOAD call race
NFS add support for asynchronous COPY
NFS COPY xdr handle async reply
NFS OFFLOAD_CANCEL xdr
NFS CB_OFFLOAD xdr
NFS: Use an appropriate work queue for direct-write completion
NFSv4: Fix error handling in nfs4_sp4_select_mode()
...
This commit is contained in:
commit
53a01c9a5f
52 changed files with 924 additions and 216 deletions
|
|
@ -753,6 +753,7 @@ out:
|
|||
case -ENODEV:
|
||||
/* Our extent block devices are unavailable */
|
||||
set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags);
|
||||
/* Fall through */
|
||||
case 0:
|
||||
return lseg;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset,
|
|||
chunk = div_u64(offset, dev->chunk_size);
|
||||
div_u64_rem(chunk, dev->nr_children, &chunk_idx);
|
||||
|
||||
if (chunk_idx > dev->nr_children) {
|
||||
if (chunk_idx >= dev->nr_children) {
|
||||
dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
|
||||
__func__, chunk_idx, offset, dev->chunk_size);
|
||||
/* error, should not happen */
|
||||
|
|
|
|||
|
|
@ -184,6 +184,18 @@ struct cb_notify_lock_args {
|
|||
extern __be32 nfs4_callback_notify_lock(void *argp, void *resp,
|
||||
struct cb_process_state *cps);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
struct cb_offloadargs {
|
||||
struct nfs_fh coa_fh;
|
||||
nfs4_stateid coa_stateid;
|
||||
uint32_t error;
|
||||
uint64_t wr_count;
|
||||
struct nfs_writeverf wr_writeverf;
|
||||
};
|
||||
|
||||
extern __be32 nfs4_callback_offload(void *args, void *dummy,
|
||||
struct cb_process_state *cps);
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
|
||||
extern __be32 nfs4_callback_getattr(void *argp, void *resp,
|
||||
struct cb_process_state *cps);
|
||||
|
|
|
|||
|
|
@ -215,9 +215,9 @@ static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo,
|
|||
{
|
||||
u32 oldseq, newseq;
|
||||
|
||||
/* Is the stateid still not initialised? */
|
||||
/* Is the stateid not initialised? */
|
||||
if (!pnfs_layout_is_valid(lo))
|
||||
return NFS4ERR_DELAY;
|
||||
return NFS4ERR_NOMATCHING_LAYOUT;
|
||||
|
||||
/* Mismatched stateid? */
|
||||
if (!nfs4_stateid_match_other(&lo->plh_stateid, new))
|
||||
|
|
@ -273,7 +273,6 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||
rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
|
||||
if (rv != NFS_OK)
|
||||
goto unlock;
|
||||
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
|
||||
|
||||
/*
|
||||
* Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
|
||||
|
|
@ -283,19 +282,23 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
||||
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
|
||||
switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
||||
&args->cbl_range,
|
||||
be32_to_cpu(args->cbl_stateid.seqid))) {
|
||||
case 0:
|
||||
case -EBUSY:
|
||||
/* There are layout segments that need to be returned */
|
||||
rv = NFS4_OK;
|
||||
goto unlock;
|
||||
}
|
||||
break;
|
||||
case -ENOENT:
|
||||
/* Embrace your forgetfulness! */
|
||||
rv = NFS4ERR_NOMATCHING_LAYOUT;
|
||||
|
||||
/* Embrace your forgetfulness! */
|
||||
rv = NFS4ERR_NOMATCHING_LAYOUT;
|
||||
|
||||
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
||||
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
||||
&args->cbl_range);
|
||||
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
||||
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
||||
&args->cbl_range);
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
spin_unlock(&ino->i_lock);
|
||||
|
|
@ -328,8 +331,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
|
|||
static u32 do_callback_layoutrecall(struct nfs_client *clp,
|
||||
struct cb_layoutrecallargs *args)
|
||||
{
|
||||
write_seqcount_begin(&clp->cl_callback_count);
|
||||
write_seqcount_end(&clp->cl_callback_count);
|
||||
if (args->cbl_recall_type == RETURN_FILE)
|
||||
return initiate_file_draining(clp, args);
|
||||
return initiate_bulk_draining(clp, args);
|
||||
|
|
@ -441,11 +442,14 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
|
|||
* a match. If the slot is in use and the sequence numbers match, the
|
||||
* client is still waiting for a response to the original request.
|
||||
*/
|
||||
static bool referring_call_exists(struct nfs_client *clp,
|
||||
static int referring_call_exists(struct nfs_client *clp,
|
||||
uint32_t nrclists,
|
||||
struct referring_call_list *rclists)
|
||||
struct referring_call_list *rclists,
|
||||
spinlock_t *lock)
|
||||
__releases(lock)
|
||||
__acquires(lock)
|
||||
{
|
||||
bool status = false;
|
||||
int status = 0;
|
||||
int i, j;
|
||||
struct nfs4_session *session;
|
||||
struct nfs4_slot_table *tbl;
|
||||
|
|
@ -468,8 +472,10 @@ static bool referring_call_exists(struct nfs_client *clp,
|
|||
|
||||
for (j = 0; j < rclist->rcl_nrefcalls; j++) {
|
||||
ref = &rclist->rcl_refcalls[j];
|
||||
spin_unlock(lock);
|
||||
status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid,
|
||||
ref->rc_sequenceid, HZ >> 1) < 0;
|
||||
spin_lock(lock);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -546,7 +552,8 @@ __be32 nfs4_callback_sequence(void *argp, void *resp,
|
|||
* related callback was received before the response to the original
|
||||
* call.
|
||||
*/
|
||||
if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
|
||||
if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists,
|
||||
&tbl->slot_tbl_lock) < 0) {
|
||||
status = htonl(NFS4ERR_DELAY);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
@ -660,3 +667,57 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp,
|
|||
return htonl(NFS4_OK);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
|
||||
struct cb_offloadargs *args)
|
||||
{
|
||||
cp_state->count = args->wr_count;
|
||||
cp_state->error = args->error;
|
||||
if (!args->error) {
|
||||
cp_state->verf.committed = args->wr_writeverf.committed;
|
||||
memcpy(&cp_state->verf.verifier.data[0],
|
||||
&args->wr_writeverf.verifier.data[0],
|
||||
NFS4_VERIFIER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
__be32 nfs4_callback_offload(void *data, void *dummy,
|
||||
struct cb_process_state *cps)
|
||||
{
|
||||
struct cb_offloadargs *args = data;
|
||||
struct nfs_server *server;
|
||||
struct nfs4_copy_state *copy;
|
||||
bool found = false;
|
||||
|
||||
spin_lock(&cps->clp->cl_lock);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
|
||||
client_link) {
|
||||
list_for_each_entry(copy, &server->ss_copies, copies) {
|
||||
if (memcmp(args->coa_stateid.other,
|
||||
copy->stateid.other,
|
||||
sizeof(args->coa_stateid.other)))
|
||||
continue;
|
||||
nfs4_copy_cb_args(copy, args);
|
||||
complete(©->completion);
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
if (!found) {
|
||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
||||
if (!copy) {
|
||||
spin_unlock(&cps->clp->cl_lock);
|
||||
return htonl(NFS4ERR_SERVERFAULT);
|
||||
}
|
||||
memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
|
||||
nfs4_copy_cb_args(copy, args);
|
||||
list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
|
||||
}
|
||||
spin_unlock(&cps->clp->cl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@
|
|||
#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
#define CB_OP_OFFLOAD_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CALLBACK
|
||||
|
||||
|
|
@ -527,7 +530,72 @@ static __be32 decode_notify_lock_args(struct svc_rqst *rqstp,
|
|||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static __be32 decode_write_response(struct xdr_stream *xdr,
|
||||
struct cb_offloadargs *args)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
/* skip the always zero field */
|
||||
p = read_buf(xdr, 4);
|
||||
if (unlikely(!p))
|
||||
goto out;
|
||||
p++;
|
||||
|
||||
/* decode count, stable_how, verifier */
|
||||
p = xdr_inline_decode(xdr, 8 + 4);
|
||||
if (unlikely(!p))
|
||||
goto out;
|
||||
p = xdr_decode_hyper(p, &args->wr_count);
|
||||
args->wr_writeverf.committed = be32_to_cpup(p);
|
||||
p = xdr_inline_decode(xdr, NFS4_VERIFIER_SIZE);
|
||||
if (likely(p)) {
|
||||
memcpy(&args->wr_writeverf.verifier.data[0], p,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
return htonl(NFS4ERR_RESOURCE);
|
||||
}
|
||||
|
||||
static __be32 decode_offload_args(struct svc_rqst *rqstp,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct cb_offloadargs *args = data;
|
||||
__be32 *p;
|
||||
__be32 status;
|
||||
|
||||
/* decode fh */
|
||||
status = decode_fh(xdr, &args->coa_fh);
|
||||
if (unlikely(status != 0))
|
||||
return status;
|
||||
|
||||
/* decode stateid */
|
||||
status = decode_stateid(xdr, &args->coa_stateid);
|
||||
if (unlikely(status != 0))
|
||||
return status;
|
||||
|
||||
/* decode status */
|
||||
p = read_buf(xdr, 4);
|
||||
if (unlikely(!p))
|
||||
goto out;
|
||||
args->error = ntohl(*p++);
|
||||
if (!args->error) {
|
||||
status = decode_write_response(xdr, args);
|
||||
if (unlikely(status != 0))
|
||||
return status;
|
||||
} else {
|
||||
p = xdr_inline_decode(xdr, 8);
|
||||
if (unlikely(!p))
|
||||
goto out;
|
||||
p = xdr_decode_hyper(p, &args->wr_count);
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
return htonl(NFS4ERR_RESOURCE);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
|
||||
{
|
||||
if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0))
|
||||
|
|
@ -773,7 +841,10 @@ preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
|
|||
if (status != htonl(NFS4ERR_OP_ILLEGAL))
|
||||
return status;
|
||||
|
||||
if (op_nr == OP_CB_OFFLOAD)
|
||||
if (op_nr == OP_CB_OFFLOAD) {
|
||||
*op = &callback_ops[op_nr];
|
||||
return htonl(NFS_OK);
|
||||
} else
|
||||
return htonl(NFS4ERR_NOTSUPP);
|
||||
return htonl(NFS4ERR_OP_ILLEGAL);
|
||||
}
|
||||
|
|
@ -883,16 +954,21 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
|
|||
|
||||
if (hdr_arg.minorversion == 0) {
|
||||
cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
|
||||
if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
|
||||
if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) {
|
||||
if (cps.clp)
|
||||
nfs_put_client(cps.clp);
|
||||
goto out_invalidcred;
|
||||
}
|
||||
}
|
||||
|
||||
cps.minorversion = hdr_arg.minorversion;
|
||||
hdr_res.taglen = hdr_arg.taglen;
|
||||
hdr_res.tag = hdr_arg.tag;
|
||||
if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
|
||||
if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) {
|
||||
if (cps.clp)
|
||||
nfs_put_client(cps.clp);
|
||||
return rpc_system_err;
|
||||
|
||||
}
|
||||
while (status == 0 && nops != hdr_arg.nops) {
|
||||
status = process_op(nops, rqstp, &xdr_in,
|
||||
rqstp->rq_argp, &xdr_out, rqstp->rq_resp,
|
||||
|
|
@ -969,6 +1045,13 @@ static struct callback_op callback_ops[] = {
|
|||
.res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ,
|
||||
},
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
[OP_CB_OFFLOAD] = {
|
||||
.process_op = nfs4_callback_offload,
|
||||
.decode_args = decode_offload_args,
|
||||
.res_maxsize = CB_OP_OFFLOAD_RES_MAXSZ,
|
||||
},
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -886,6 +886,7 @@ struct nfs_server *nfs_alloc_server(void)
|
|||
INIT_LIST_HEAD(&server->delegations);
|
||||
INIT_LIST_HEAD(&server->layouts);
|
||||
INIT_LIST_HEAD(&server->state_owners_lru);
|
||||
INIT_LIST_HEAD(&server->ss_copies);
|
||||
|
||||
atomic_set(&server->active, 0);
|
||||
|
||||
|
|
|
|||
32
fs/nfs/dir.c
32
fs/nfs/dir.c
|
|
@ -904,23 +904,29 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
|
|||
dfprintk(FILE, "NFS: llseek dir(%pD2, %lld, %d)\n",
|
||||
filp, offset, whence);
|
||||
|
||||
inode_lock(inode);
|
||||
switch (whence) {
|
||||
case 1:
|
||||
offset += filp->f_pos;
|
||||
case 0:
|
||||
if (offset >= 0)
|
||||
break;
|
||||
default:
|
||||
offset = -EINVAL;
|
||||
goto out;
|
||||
default:
|
||||
return -EINVAL;
|
||||
case SEEK_SET:
|
||||
if (offset < 0)
|
||||
return -EINVAL;
|
||||
inode_lock(inode);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if (offset == 0)
|
||||
return filp->f_pos;
|
||||
inode_lock(inode);
|
||||
offset += filp->f_pos;
|
||||
if (offset < 0) {
|
||||
inode_unlock(inode);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (offset != filp->f_pos) {
|
||||
filp->f_pos = offset;
|
||||
dir_ctx->dir_cookie = 0;
|
||||
dir_ctx->duped = 0;
|
||||
}
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
return offset;
|
||||
}
|
||||
|
|
@ -1032,7 +1038,7 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
|
|||
if (flags & LOOKUP_REVAL)
|
||||
goto out_force;
|
||||
out:
|
||||
return (inode->i_nlink == 0) ? -ENOENT : 0;
|
||||
return (inode->i_nlink == 0) ? -ESTALE : 0;
|
||||
out_force:
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
|
@ -2499,7 +2505,9 @@ static int nfs_execute_ok(struct inode *inode, int mask)
|
|||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
int ret = 0;
|
||||
|
||||
if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS)) {
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
return 0;
|
||||
if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_OTHER)) {
|
||||
if (mask & MAY_NOT_BLOCK)
|
||||
return -ECHILD;
|
||||
ret = __nfs_revalidate_inode(server, inode);
|
||||
|
|
|
|||
|
|
@ -758,7 +758,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
|
|||
|
||||
static void nfs_direct_write_complete(struct nfs_direct_req *dreq)
|
||||
{
|
||||
schedule_work(&dreq->work); /* Calls nfs_direct_write_schedule_work */
|
||||
queue_work(nfsiod_workqueue, &dreq->work); /* Calls nfs_direct_write_schedule_work */
|
||||
}
|
||||
|
||||
static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
||||
|
|
|
|||
|
|
@ -532,13 +532,13 @@ const struct address_space_operations nfs_file_aops = {
|
|||
* writable, implying that someone is about to modify the page through a
|
||||
* shared-writable mapping
|
||||
*/
|
||||
static int nfs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
static vm_fault_t nfs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
{
|
||||
struct page *page = vmf->page;
|
||||
struct file *filp = vmf->vma->vm_file;
|
||||
struct inode *inode = file_inode(filp);
|
||||
unsigned pagelen;
|
||||
int ret = VM_FAULT_NOPAGE;
|
||||
vm_fault_t ret = VM_FAULT_NOPAGE;
|
||||
struct address_space *mapping;
|
||||
|
||||
dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n",
|
||||
|
|
|
|||
|
|
@ -812,7 +812,6 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,
|
|||
struct nfs_page *req,
|
||||
bool strict_iomode)
|
||||
{
|
||||
retry_strict:
|
||||
pnfs_put_lseg(pgio->pg_lseg);
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
|
|
@ -825,16 +824,6 @@ retry_strict:
|
|||
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
|
||||
pgio->pg_lseg = NULL;
|
||||
}
|
||||
|
||||
/* If we don't have checking, do get a IOMODE_RW
|
||||
* segment, and the server wants to avoid READs
|
||||
* there, then retry!
|
||||
*/
|
||||
if (pgio->pg_lseg && !strict_iomode &&
|
||||
ff_layout_avoid_read_on_rw(pgio->pg_lseg)) {
|
||||
strict_iomode = true;
|
||||
goto retry_strict;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -849,14 +838,16 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
|
|||
retry:
|
||||
pnfs_generic_pg_check_layout(pgio);
|
||||
/* Use full layout for now */
|
||||
if (!pgio->pg_lseg)
|
||||
if (!pgio->pg_lseg) {
|
||||
ff_layout_pg_get_read(pgio, req, false);
|
||||
else if (ff_layout_avoid_read_on_rw(pgio->pg_lseg))
|
||||
if (!pgio->pg_lseg)
|
||||
goto out_nolseg;
|
||||
}
|
||||
if (ff_layout_avoid_read_on_rw(pgio->pg_lseg)) {
|
||||
ff_layout_pg_get_read(pgio, req, true);
|
||||
|
||||
/* If no lseg, fall back to read through mds */
|
||||
if (pgio->pg_lseg == NULL)
|
||||
goto out_mds;
|
||||
if (!pgio->pg_lseg)
|
||||
goto out_nolseg;
|
||||
}
|
||||
|
||||
ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx);
|
||||
if (!ds) {
|
||||
|
|
@ -878,6 +869,9 @@ retry:
|
|||
pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
|
||||
|
||||
return;
|
||||
out_nolseg:
|
||||
if (pgio->pg_error < 0)
|
||||
return;
|
||||
out_mds:
|
||||
pnfs_put_lseg(pgio->pg_lseg);
|
||||
pgio->pg_lseg = NULL;
|
||||
|
|
@ -1323,6 +1317,7 @@ static void ff_layout_read_record_layoutstats_done(struct rpc_task *task,
|
|||
FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
|
||||
hdr->args.count,
|
||||
hdr->res.count);
|
||||
set_bit(NFS_LSEG_LAYOUTRETURN, &hdr->lseg->pls_flags);
|
||||
}
|
||||
|
||||
static int ff_layout_read_prepare_common(struct rpc_task *task,
|
||||
|
|
@ -1507,6 +1502,7 @@ static void ff_layout_write_record_layoutstats_done(struct rpc_task *task,
|
|||
FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
|
||||
hdr->args.count, hdr->res.count,
|
||||
hdr->res.verf->committed);
|
||||
set_bit(NFS_LSEG_LAYOUTRETURN, &hdr->lseg->pls_flags);
|
||||
}
|
||||
|
||||
static int ff_layout_write_prepare_common(struct rpc_task *task,
|
||||
|
|
@ -1615,6 +1611,7 @@ static void ff_layout_commit_record_layoutstats_done(struct rpc_task *task,
|
|||
nfs4_ff_layout_stat_io_end_write(task,
|
||||
FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index),
|
||||
count, count, NFS_FILE_SYNC);
|
||||
set_bit(NFS_LSEG_LAYOUTRETURN, &cdata->lseg->pls_flags);
|
||||
}
|
||||
|
||||
static void ff_layout_commit_prepare_common(struct rpc_task *task,
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
|
|||
case -EPROTONOSUPPORT:
|
||||
dprintk("NFS_V3_ACL extension not supported; disabling\n");
|
||||
server->caps &= ~NFS_CAP_ACLS;
|
||||
/* fall through */
|
||||
case -ENOTSUPP:
|
||||
status = -EOPNOTSUPP;
|
||||
default:
|
||||
|
|
@ -229,6 +230,7 @@ static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
|
|||
dprintk("NFS_V3_ACL SETACL RPC not supported"
|
||||
"(will not retry)\n");
|
||||
server->caps &= ~NFS_CAP_ACLS;
|
||||
/* fall through */
|
||||
case -ENOTSUPP:
|
||||
status = -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
|
||||
|
||||
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
|
||||
struct nfs_lock_context *lock, loff_t offset, loff_t len)
|
||||
|
|
@ -130,6 +131,91 @@ out_unlock:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int handle_async_copy(struct nfs42_copy_res *res,
|
||||
struct nfs_server *server,
|
||||
struct file *src,
|
||||
struct file *dst,
|
||||
nfs4_stateid *src_stateid)
|
||||
{
|
||||
struct nfs4_copy_state *copy;
|
||||
int status = NFS4_OK;
|
||||
bool found_pending = false;
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(dst);
|
||||
|
||||
spin_lock(&server->nfs_client->cl_lock);
|
||||
list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
|
||||
copies) {
|
||||
if (memcmp(&res->write_res.stateid, ©->stateid,
|
||||
NFS4_STATEID_SIZE))
|
||||
continue;
|
||||
found_pending = true;
|
||||
list_del(©->copies);
|
||||
break;
|
||||
}
|
||||
if (found_pending) {
|
||||
spin_unlock(&server->nfs_client->cl_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
||||
if (!copy) {
|
||||
spin_unlock(&server->nfs_client->cl_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
||||
init_completion(©->completion);
|
||||
copy->parent_state = ctx->state;
|
||||
|
||||
list_add_tail(©->copies, &server->ss_copies);
|
||||
spin_unlock(&server->nfs_client->cl_lock);
|
||||
|
||||
status = wait_for_completion_interruptible(©->completion);
|
||||
spin_lock(&server->nfs_client->cl_lock);
|
||||
list_del_init(©->copies);
|
||||
spin_unlock(&server->nfs_client->cl_lock);
|
||||
if (status == -ERESTARTSYS) {
|
||||
goto out_cancel;
|
||||
} else if (copy->flags) {
|
||||
status = -EAGAIN;
|
||||
goto out_cancel;
|
||||
}
|
||||
out:
|
||||
res->write_res.count = copy->count;
|
||||
memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
|
||||
status = -copy->error;
|
||||
|
||||
kfree(copy);
|
||||
return status;
|
||||
out_cancel:
|
||||
nfs42_do_offload_cancel_async(dst, ©->stateid);
|
||||
kfree(copy);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int process_copy_commit(struct file *dst, loff_t pos_dst,
|
||||
struct nfs42_copy_res *res)
|
||||
{
|
||||
struct nfs_commitres cres;
|
||||
int status = -ENOMEM;
|
||||
|
||||
cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
|
||||
if (!cres.verf)
|
||||
goto out;
|
||||
|
||||
status = nfs4_proc_commit(dst, pos_dst, res->write_res.count, &cres);
|
||||
if (status)
|
||||
goto out_free;
|
||||
if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
|
||||
&cres.verf->verifier)) {
|
||||
dprintk("commit verf differs from copy verf\n");
|
||||
status = -EAGAIN;
|
||||
}
|
||||
out_free:
|
||||
kfree(cres.verf);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t _nfs42_proc_copy(struct file *src,
|
||||
struct nfs_lock_context *src_lock,
|
||||
struct file *dst,
|
||||
|
|
@ -168,9 +254,16 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
|
||||
if (!res->commit_res.verf)
|
||||
return -ENOMEM;
|
||||
res->commit_res.verf = NULL;
|
||||
if (args->sync) {
|
||||
res->commit_res.verf =
|
||||
kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
|
||||
if (!res->commit_res.verf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
||||
&dst_lock->open_context->state->flags);
|
||||
|
||||
status = nfs4_call_sync(server->client, server, &msg,
|
||||
&args->seq_args, &res->seq_res, 0);
|
||||
if (status == -ENOTSUPP)
|
||||
|
|
@ -178,18 +271,34 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||
if (status)
|
||||
goto out;
|
||||
|
||||
if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
|
||||
if (args->sync &&
|
||||
nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
|
||||
&res->commit_res.verf->verifier)) {
|
||||
status = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!res->synchronous) {
|
||||
status = handle_async_copy(res, server, src, dst,
|
||||
&args->src_stateid);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((!res->synchronous || !args->sync) &&
|
||||
res->write_res.verifier.committed != NFS_FILE_SYNC) {
|
||||
status = process_copy_commit(dst, pos_dst, res);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
truncate_pagecache_range(dst_inode, pos_dst,
|
||||
pos_dst + res->write_res.count);
|
||||
|
||||
status = res->write_res.count;
|
||||
out:
|
||||
kfree(res->commit_res.verf);
|
||||
if (args->sync)
|
||||
kfree(res->commit_res.verf);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +315,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
|||
.dst_fh = NFS_FH(file_inode(dst)),
|
||||
.dst_pos = pos_dst,
|
||||
.count = count,
|
||||
.sync = false,
|
||||
};
|
||||
struct nfs42_copy_res res;
|
||||
struct nfs4_exception src_exception = {
|
||||
|
|
@ -247,7 +357,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
|||
if (err == -ENOTSUPP) {
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
} if (err == -EAGAIN) {
|
||||
} else if (err == -EAGAIN) {
|
||||
dst_exception.retry = 1;
|
||||
continue;
|
||||
} else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
|
||||
args.sync = true;
|
||||
dst_exception.retry = 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -264,6 +378,89 @@ out_put_src_lock:
|
|||
return err;
|
||||
}
|
||||
|
||||
struct nfs42_offloadcancel_data {
|
||||
struct nfs_server *seq_server;
|
||||
struct nfs42_offload_status_args args;
|
||||
struct nfs42_offload_status_res res;
|
||||
};
|
||||
|
||||
static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs42_offloadcancel_data *data = calldata;
|
||||
|
||||
nfs4_setup_sequence(data->seq_server->nfs_client,
|
||||
&data->args.osa_seq_args,
|
||||
&data->res.osr_seq_res, task);
|
||||
}
|
||||
|
||||
static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs42_offloadcancel_data *data = calldata;
|
||||
|
||||
nfs41_sequence_done(task, &data->res.osr_seq_res);
|
||||
if (task->tk_status &&
|
||||
nfs4_async_handle_error(task, data->seq_server, NULL,
|
||||
NULL) == -EAGAIN)
|
||||
rpc_restart_call_prepare(task);
|
||||
}
|
||||
|
||||
static void nfs42_free_offloadcancel_data(void *data)
|
||||
{
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs42_offload_cancel_ops = {
|
||||
.rpc_call_prepare = nfs42_offload_cancel_prepare,
|
||||
.rpc_call_done = nfs42_offload_cancel_done,
|
||||
.rpc_release = nfs42_free_offloadcancel_data,
|
||||
};
|
||||
|
||||
static int nfs42_do_offload_cancel_async(struct file *dst,
|
||||
nfs4_stateid *stateid)
|
||||
{
|
||||
struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
|
||||
struct nfs42_offloadcancel_data *data = NULL;
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(dst);
|
||||
struct rpc_task *task;
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL],
|
||||
.rpc_cred = ctx->cred,
|
||||
};
|
||||
struct rpc_task_setup task_setup_data = {
|
||||
.rpc_client = dst_server->client,
|
||||
.rpc_message = &msg,
|
||||
.callback_ops = &nfs42_offload_cancel_ops,
|
||||
.workqueue = nfsiod_workqueue,
|
||||
.flags = RPC_TASK_ASYNC,
|
||||
};
|
||||
int status;
|
||||
|
||||
if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data->seq_server = dst_server;
|
||||
data->args.osa_src_fh = NFS_FH(file_inode(dst));
|
||||
memcpy(&data->args.osa_stateid, stateid,
|
||||
sizeof(data->args.osa_stateid));
|
||||
msg.rpc_argp = &data->args;
|
||||
msg.rpc_resp = &data->res;
|
||||
task_setup_data.callback_data = data;
|
||||
nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res,
|
||||
1, 0);
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
status = rpc_wait_for_completion_task(task);
|
||||
if (status == -ENOTSUPP)
|
||||
dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL;
|
||||
rpc_put_task(task);
|
||||
return status;
|
||||
}
|
||||
|
||||
static loff_t _nfs42_proc_llseek(struct file *filep,
|
||||
struct nfs_lock_context *lock, loff_t offset, int whence)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
NFS42_WRITE_RES_SIZE + \
|
||||
1 /* cr_consecutive */ + \
|
||||
1 /* cr_synchronous */)
|
||||
#define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \
|
||||
XDR_QUADLEN(NFS4_STATEID_SIZE))
|
||||
#define decode_offload_cancel_maxsz (op_decode_hdr_maxsz)
|
||||
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
|
||||
encode_fallocate_maxsz)
|
||||
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
|
||||
|
|
@ -75,6 +78,12 @@
|
|||
decode_putfh_maxsz + \
|
||||
decode_copy_maxsz + \
|
||||
decode_commit_maxsz)
|
||||
#define NFS4_enc_offload_cancel_sz (compound_encode_hdr_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_offload_cancel_maxsz)
|
||||
#define NFS4_dec_offload_cancel_sz (compound_decode_hdr_maxsz + \
|
||||
decode_putfh_maxsz + \
|
||||
decode_offload_cancel_maxsz)
|
||||
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_deallocate_maxsz + \
|
||||
|
|
@ -141,10 +150,18 @@ static void encode_copy(struct xdr_stream *xdr,
|
|||
encode_uint64(xdr, args->count);
|
||||
|
||||
encode_uint32(xdr, 1); /* consecutive = true */
|
||||
encode_uint32(xdr, 1); /* synchronous = true */
|
||||
encode_uint32(xdr, args->sync);
|
||||
encode_uint32(xdr, 0); /* src server list */
|
||||
}
|
||||
|
||||
static void encode_offload_cancel(struct xdr_stream *xdr,
|
||||
const struct nfs42_offload_status_args *args,
|
||||
struct compound_hdr *hdr)
|
||||
{
|
||||
encode_op_hdr(xdr, OP_OFFLOAD_CANCEL, decode_offload_cancel_maxsz, hdr);
|
||||
encode_nfs4_stateid(xdr, &args->osa_stateid);
|
||||
}
|
||||
|
||||
static void encode_deallocate(struct xdr_stream *xdr,
|
||||
const struct nfs42_falloc_args *args,
|
||||
struct compound_hdr *hdr)
|
||||
|
|
@ -256,7 +273,27 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
|
|||
encode_savefh(xdr, &hdr);
|
||||
encode_putfh(xdr, args->dst_fh, &hdr);
|
||||
encode_copy(xdr, args, &hdr);
|
||||
encode_copy_commit(xdr, args, &hdr);
|
||||
if (args->sync)
|
||||
encode_copy_commit(xdr, args, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode OFFLOAD_CANEL request
|
||||
*/
|
||||
static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nfs42_offload_status_args *args = data;
|
||||
struct compound_hdr hdr = {
|
||||
.minorversion = nfs4_xdr_minorversion(&args->osa_seq_args),
|
||||
};
|
||||
|
||||
encode_compound_hdr(xdr, req, &hdr);
|
||||
encode_sequence(xdr, &args->osa_seq_args, &hdr);
|
||||
encode_putfh(xdr, args->osa_src_fh, &hdr);
|
||||
encode_offload_cancel(xdr, args, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
||||
|
|
@ -353,21 +390,23 @@ static int decode_write_response(struct xdr_stream *xdr,
|
|||
struct nfs42_write_res *res)
|
||||
{
|
||||
__be32 *p;
|
||||
int status, count;
|
||||
|
||||
p = xdr_inline_decode(xdr, 4 + 8 + 4);
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(!p))
|
||||
goto out_overflow;
|
||||
|
||||
/*
|
||||
* We never use asynchronous mode, so warn if a server returns
|
||||
* a stateid.
|
||||
*/
|
||||
if (unlikely(*p != 0)) {
|
||||
pr_err_once("%s: server has set unrequested "
|
||||
"asynchronous mode\n", __func__);
|
||||
count = be32_to_cpup(p);
|
||||
if (count > 1)
|
||||
return -EREMOTEIO;
|
||||
else if (count == 1) {
|
||||
status = decode_opaque_fixed(xdr, &res->stateid,
|
||||
NFS4_STATEID_SIZE);
|
||||
if (unlikely(status))
|
||||
goto out_overflow;
|
||||
}
|
||||
p++;
|
||||
p = xdr_inline_decode(xdr, 8 + 4);
|
||||
if (unlikely(!p))
|
||||
goto out_overflow;
|
||||
p = xdr_decode_hyper(p, &res->count);
|
||||
res->verifier.committed = be32_to_cpup(p);
|
||||
return decode_verifier(xdr, &res->verifier.verifier);
|
||||
|
|
@ -413,6 +452,12 @@ static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
|
|||
return decode_copy_requirements(xdr, res);
|
||||
}
|
||||
|
||||
static int decode_offload_cancel(struct xdr_stream *xdr,
|
||||
struct nfs42_offload_status_res *res)
|
||||
{
|
||||
return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
|
||||
}
|
||||
|
||||
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
|
||||
{
|
||||
return decode_op_hdr(xdr, OP_DEALLOCATE);
|
||||
|
|
@ -507,7 +552,34 @@ static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
|
|||
status = decode_copy(xdr, res);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_commit(xdr, &res->commit_res);
|
||||
if (res->commit_res.verf)
|
||||
status = decode_commit(xdr, &res->commit_res);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode OFFLOAD_CANCEL response
|
||||
*/
|
||||
static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nfs42_offload_status_res *res = data;
|
||||
struct compound_hdr hdr;
|
||||
int status;
|
||||
|
||||
status = decode_compound_hdr(xdr, &hdr);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_sequence(xdr, &res->osr_seq_res, rqstp);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_putfh(xdr);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_offload_cancel(xdr, res);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,9 @@ enum {
|
|||
NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
|
||||
NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */
|
||||
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
};
|
||||
|
||||
struct nfs4_state {
|
||||
|
|
@ -273,6 +276,9 @@ int nfs4_replace_transport(struct nfs_server *server,
|
|||
|
||||
/* nfs4proc.c */
|
||||
extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
|
||||
extern int nfs4_async_handle_error(struct rpc_task *task,
|
||||
struct nfs_server *server,
|
||||
struct nfs4_state *state, long *timeout);
|
||||
extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
|
||||
struct rpc_message *, struct nfs4_sequence_args *,
|
||||
struct nfs4_sequence_res *, int);
|
||||
|
|
@ -505,7 +511,7 @@ extern int nfs4_sequence_done(struct rpc_task *task,
|
|||
struct nfs4_sequence_res *res);
|
||||
|
||||
extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp);
|
||||
|
||||
extern int nfs4_proc_commit(struct file *dst, __u64 offset, __u32 count, struct nfs_commitres *res);
|
||||
extern const nfs4_stateid zero_stateid;
|
||||
extern const nfs4_stateid invalid_stateid;
|
||||
|
||||
|
|
|
|||
|
|
@ -156,9 +156,23 @@ nfs4_shutdown_ds_clients(struct nfs_client *clp)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nfs4_cleanup_callback(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_copy_state *cp_state;
|
||||
|
||||
while (!list_empty(&clp->pending_cb_stateids)) {
|
||||
cp_state = list_entry(clp->pending_cb_stateids.next,
|
||||
struct nfs4_copy_state, copies);
|
||||
list_del(&cp_state->copies);
|
||||
kfree(cp_state);
|
||||
}
|
||||
}
|
||||
|
||||
void nfs41_shutdown_client(struct nfs_client *clp)
|
||||
{
|
||||
if (nfs4_has_session(clp)) {
|
||||
nfs4_cleanup_callback(clp);
|
||||
nfs4_shutdown_ds_clients(clp);
|
||||
nfs4_destroy_session(clp->cl_session);
|
||||
nfs4_destroy_clientid(clp);
|
||||
|
|
@ -202,6 +216,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
init_waitqueue_head(&clp->cl_lock_waitq);
|
||||
#endif
|
||||
INIT_LIST_HEAD(&clp->pending_cb_stateids);
|
||||
return clp;
|
||||
|
||||
error:
|
||||
|
|
@ -1127,7 +1142,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
|
|||
nfs_server_copy_userdata(server, parent_server);
|
||||
|
||||
/* Get a client representation */
|
||||
#ifdef CONFIG_SUNRPC_XPRT_RDMA
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
|
||||
rpc_set_port(data->addr, NFS_RDMA_PORT);
|
||||
error = nfs4_set_client(server, data->hostname,
|
||||
data->addr,
|
||||
|
|
@ -1139,7 +1154,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
|
|||
parent_client->cl_net);
|
||||
if (!error)
|
||||
goto init_server;
|
||||
#endif /* CONFIG_SUNRPC_XPRT_RDMA */
|
||||
#endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
|
||||
|
||||
rpc_set_port(data->addr, NFS_PORT);
|
||||
error = nfs4_set_client(server, data->hostname,
|
||||
|
|
@ -1153,7 +1168,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
|
|||
if (error < 0)
|
||||
goto error;
|
||||
|
||||
#ifdef CONFIG_SUNRPC_XPRT_RDMA
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
|
||||
init_server:
|
||||
#endif
|
||||
error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
|
||||
|
|
|
|||
|
|
@ -133,10 +133,15 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
struct file *file_out, loff_t pos_out,
|
||||
size_t count, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (file_inode(file_in) == file_inode(file_out))
|
||||
return -EINVAL;
|
||||
|
||||
return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
|
||||
retry:
|
||||
ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
|
||||
|
|
@ -149,6 +154,7 @@ static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
|
|||
ret = nfs42_proc_llseek(filep, offset, whence);
|
||||
if (ret != -ENOTSUPP)
|
||||
return ret;
|
||||
/* Fall through */
|
||||
default:
|
||||
return nfs_file_llseek(filep, offset, whence);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,6 +506,7 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
|
|||
switch (token) {
|
||||
case Opt_find_uid:
|
||||
im->im_type = IDMAP_TYPE_USER;
|
||||
/* Fall through */
|
||||
case Opt_find_gid:
|
||||
im->im_conv = IDMAP_CONV_NAMETOID;
|
||||
ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
|
||||
|
|
@ -513,9 +514,12 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
|
|||
|
||||
case Opt_find_user:
|
||||
im->im_type = IDMAP_TYPE_USER;
|
||||
/* Fall through */
|
||||
case Opt_find_group:
|
||||
im->im_conv = IDMAP_CONV_IDTONAME;
|
||||
ret = match_int(&substr, &im->im_id);
|
||||
if (ret)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -449,6 +449,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
|
|||
stateid);
|
||||
goto wait_on_recovery;
|
||||
}
|
||||
/* Fall through */
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (inode) {
|
||||
int err;
|
||||
|
|
@ -501,8 +502,10 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
|
|||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case -NFS4ERR_DELAY:
|
||||
nfs_inc_server_stats(server, NFSIOS_DELAY);
|
||||
/* Fall through */
|
||||
case -NFS4ERR_GRACE:
|
||||
case -NFS4ERR_LAYOUTTRYLATER:
|
||||
case -NFS4ERR_RECALLCONFLICT:
|
||||
|
|
@ -581,12 +584,19 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
|
|||
ret = -EIO;
|
||||
return ret;
|
||||
out_retry:
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
exception->retry = 1;
|
||||
/*
|
||||
* For NFS4ERR_MOVED, the client transport will need to
|
||||
* be recomputed after migration recovery has completed.
|
||||
*/
|
||||
if (errorcode == -NFS4ERR_MOVED)
|
||||
rpc_task_release_transport(task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server,
|
||||
struct nfs4_state *state, long *timeout)
|
||||
{
|
||||
|
|
@ -1071,15 +1081,30 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
|
|||
return nfs4_call_sync_sequence(clnt, server, msg, args, res);
|
||||
}
|
||||
|
||||
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
unsigned long timestamp)
|
||||
static void
|
||||
nfs4_inc_nlink_locked(struct inode *inode)
|
||||
{
|
||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
|
||||
inc_nlink(inode);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs4_dec_nlink_locked(struct inode *inode)
|
||||
{
|
||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
|
||||
drop_nlink(inode);
|
||||
}
|
||||
|
||||
static void
|
||||
update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
unsigned long timestamp, unsigned long cache_validity)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(dir);
|
||||
|
||||
spin_lock(&dir->i_lock);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_CTIME
|
||||
| NFS_INO_INVALID_MTIME
|
||||
| NFS_INO_INVALID_DATA;
|
||||
| NFS_INO_INVALID_DATA
|
||||
| cache_validity;
|
||||
if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(dir)) {
|
||||
nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
|
||||
nfsi->attrtimeo_timestamp = jiffies;
|
||||
|
|
@ -1092,7 +1117,16 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
|||
inode_set_iversion_raw(dir, cinfo->after);
|
||||
nfsi->read_cache_jiffies = timestamp;
|
||||
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
|
||||
nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE;
|
||||
nfs_fscache_invalidate(dir);
|
||||
}
|
||||
|
||||
static void
|
||||
update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
unsigned long timestamp, unsigned long cache_validity)
|
||||
{
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, cinfo, timestamp, cache_validity);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1354,6 +1388,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
|
|||
case NFS4_OPEN_CLAIM_PREVIOUS:
|
||||
if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
|
||||
break;
|
||||
/* Fall through */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1773,6 +1808,10 @@ nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
|
|||
data->o_res.delegation_type,
|
||||
&data->o_res.delegation,
|
||||
data->o_res.pagemod_limit);
|
||||
|
||||
if (data->o_res.do_recall)
|
||||
nfs_async_inode_return_delegation(state->inode,
|
||||
&data->o_res.delegation);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2119,6 +2158,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
|
|||
err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
|
||||
if (err)
|
||||
break;
|
||||
/* Fall through */
|
||||
case FMODE_READ:
|
||||
err = nfs4_open_recover_helper(opendata, FMODE_READ);
|
||||
}
|
||||
|
|
@ -2248,6 +2288,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|||
case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
|
||||
case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
|
||||
data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
|
||||
/* Fall through */
|
||||
case NFS4_OPEN_CLAIM_FH:
|
||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
||||
}
|
||||
|
|
@ -2481,7 +2522,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data,
|
|||
if (data->file_created ||
|
||||
inode_peek_iversion_raw(dir) != o_res->cinfo.after)
|
||||
update_changeattr(dir, &o_res->cinfo,
|
||||
o_res->f_attr->time_start);
|
||||
o_res->f_attr->time_start, 0);
|
||||
}
|
||||
if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
|
||||
server->caps &= ~NFS_CAP_POSIX_LOCK;
|
||||
|
|
@ -2843,6 +2884,9 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|||
nfs_save_change_attribute(d_inode(opendata->dir)));
|
||||
}
|
||||
|
||||
/* Parse layoutget results before we check for access */
|
||||
pnfs_parse_lgopen(state->inode, opendata->lgp, ctx);
|
||||
|
||||
ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
|
@ -2851,8 +2895,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|||
nfs_inode_attach_open_context(ctx);
|
||||
if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
else
|
||||
pnfs_parse_lgopen(state->inode, opendata->lgp, ctx);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -3220,7 +3262,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|||
calldata->res.lr_res = NULL;
|
||||
break;
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
if (nfs4_refresh_layout_stateid(&calldata->arg.lr_args->stateid,
|
||||
if (nfs4_layoutreturn_refresh_stateid(&calldata->arg.lr_args->stateid,
|
||||
&calldata->arg.lr_args->range,
|
||||
calldata->inode))
|
||||
goto lr_restart;
|
||||
/* Fallthrough */
|
||||
|
|
@ -4236,7 +4279,8 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
|
||||
static int
|
||||
_nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs_removeargs args = {
|
||||
|
|
@ -4255,8 +4299,14 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
|
|||
int status;
|
||||
|
||||
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
|
||||
if (status == 0)
|
||||
update_changeattr(dir, &res.cinfo, timestamp);
|
||||
if (status == 0) {
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, &res.cinfo, timestamp, 0);
|
||||
/* Removing a directory decrements nlink in the parent */
|
||||
if (ftype == NF4DIR && dir->i_nlink > 2)
|
||||
nfs4_dec_nlink_locked(dir);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -4273,7 +4323,7 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
|
|||
nfs4_inode_make_writeable(inode);
|
||||
}
|
||||
do {
|
||||
err = _nfs4_proc_remove(dir, &dentry->d_name);
|
||||
err = _nfs4_proc_remove(dir, &dentry->d_name, NF4REG);
|
||||
trace_nfs4_remove(dir, &dentry->d_name, err);
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir), err,
|
||||
&exception);
|
||||
|
|
@ -4287,7 +4337,7 @@ static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
|
|||
int err;
|
||||
|
||||
do {
|
||||
err = _nfs4_proc_remove(dir, name);
|
||||
err = _nfs4_proc_remove(dir, name, NF4DIR);
|
||||
trace_nfs4_remove(dir, name, err);
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir), err,
|
||||
&exception);
|
||||
|
|
@ -4331,7 +4381,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
|
|||
&data->timeout) == -EAGAIN)
|
||||
return 0;
|
||||
if (task->tk_status == 0)
|
||||
update_changeattr(dir, &res->cinfo, res->dir_attr->time_start);
|
||||
update_changeattr(dir, &res->cinfo,
|
||||
res->dir_attr->time_start, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -4373,9 +4424,18 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
|
|||
return 0;
|
||||
|
||||
if (task->tk_status == 0) {
|
||||
update_changeattr(old_dir, &res->old_cinfo, res->old_fattr->time_start);
|
||||
if (new_dir != old_dir)
|
||||
update_changeattr(new_dir, &res->new_cinfo, res->new_fattr->time_start);
|
||||
if (new_dir != old_dir) {
|
||||
/* Note: If we moved a directory, nlink will change */
|
||||
update_changeattr(old_dir, &res->old_cinfo,
|
||||
res->old_fattr->time_start,
|
||||
NFS_INO_INVALID_OTHER);
|
||||
update_changeattr(new_dir, &res->new_cinfo,
|
||||
res->new_fattr->time_start,
|
||||
NFS_INO_INVALID_OTHER);
|
||||
} else
|
||||
update_changeattr(old_dir, &res->old_cinfo,
|
||||
res->old_fattr->time_start,
|
||||
0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -4416,7 +4476,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct
|
|||
|
||||
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
|
||||
if (!status) {
|
||||
update_changeattr(dir, &res.cinfo, res.fattr->time_start);
|
||||
update_changeattr(dir, &res.cinfo, res.fattr->time_start, 0);
|
||||
status = nfs_post_op_update_inode(inode, res.fattr);
|
||||
if (!status)
|
||||
nfs_setsecurity(inode, res.fattr, res.label);
|
||||
|
|
@ -4491,8 +4551,13 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
|
|||
int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
|
||||
&data->arg.seq_args, &data->res.seq_res, 1);
|
||||
if (status == 0) {
|
||||
update_changeattr(dir, &data->res.dir_cinfo,
|
||||
data->res.fattr->time_start);
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, &data->res.dir_cinfo,
|
||||
data->res.fattr->time_start, 0);
|
||||
/* Creating a directory bumps nlink in the parent */
|
||||
if (data->arg.ftype == NF4DIR)
|
||||
nfs4_inc_nlink_locked(dir);
|
||||
spin_unlock(&dir->i_lock);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
|
||||
}
|
||||
return status;
|
||||
|
|
@ -5073,6 +5138,40 @@ static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
|
|||
nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
|
||||
}
|
||||
|
||||
static int _nfs4_proc_commit(struct file *dst, struct nfs_commitargs *args,
|
||||
struct nfs_commitres *res)
|
||||
{
|
||||
struct inode *dst_inode = file_inode(dst);
|
||||
struct nfs_server *server = NFS_SERVER(dst_inode);
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
|
||||
.rpc_argp = args,
|
||||
.rpc_resp = res,
|
||||
};
|
||||
|
||||
args->fh = NFS_FH(dst_inode);
|
||||
return nfs4_call_sync(server->client, server, &msg,
|
||||
&args->seq_args, &res->seq_res, 1);
|
||||
}
|
||||
|
||||
int nfs4_proc_commit(struct file *dst, __u64 offset, __u32 count, struct nfs_commitres *res)
|
||||
{
|
||||
struct nfs_commitargs args = {
|
||||
.offset = offset,
|
||||
.count = count,
|
||||
};
|
||||
struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
|
||||
struct nfs4_exception exception = { };
|
||||
int status;
|
||||
|
||||
do {
|
||||
status = _nfs4_proc_commit(dst, &args, res);
|
||||
status = nfs4_handle_exception(dst_server, status, &exception);
|
||||
} while (exception.retry);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
struct nfs4_renewdata {
|
||||
struct nfs_client *client;
|
||||
unsigned long timestamp;
|
||||
|
|
@ -5902,7 +6001,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
|||
data->res.lr_res = NULL;
|
||||
break;
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
if (nfs4_refresh_layout_stateid(&data->args.lr_args->stateid,
|
||||
if (nfs4_layoutreturn_refresh_stateid(&data->args.lr_args->stateid,
|
||||
&data->args.lr_args->range,
|
||||
data->inode))
|
||||
goto lr_restart;
|
||||
/* Fallthrough */
|
||||
|
|
@ -6209,11 +6309,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
|||
if (nfs4_update_lock_stateid(calldata->lsp,
|
||||
&calldata->res.stateid))
|
||||
break;
|
||||
/* Fall through */
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
nfs4_free_revoked_stateid(calldata->server,
|
||||
&calldata->arg.stateid,
|
||||
task->tk_msg.rpc_cred);
|
||||
/* Fall through */
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
|
|
@ -7727,7 +7829,7 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
|
|||
}
|
||||
out:
|
||||
clp->cl_sp4_flags = flags;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct nfs41_exchange_id_data {
|
||||
|
|
@ -8168,7 +8270,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
|
|||
args->bc_attrs.max_resp_sz = max_bc_payload;
|
||||
args->bc_attrs.max_resp_sz_cached = 0;
|
||||
args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
|
||||
args->bc_attrs.max_reqs = min_t(unsigned short, max_session_cb_slots, 1);
|
||||
args->bc_attrs.max_reqs = max_t(unsigned short, max_session_cb_slots, 1);
|
||||
|
||||
dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
|
||||
"max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
|
||||
|
|
@ -8851,7 +8953,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
|
|||
server = NFS_SERVER(lrp->args.inode);
|
||||
switch (task->tk_status) {
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
if (nfs4_refresh_layout_stateid(&lrp->args.stateid,
|
||||
if (nfs4_layoutreturn_refresh_stateid(&lrp->args.stateid,
|
||||
&lrp->args.range,
|
||||
lrp->args.inode))
|
||||
goto out_restart;
|
||||
/* Fallthrough */
|
||||
|
|
@ -9554,6 +9657,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
|||
| NFS_CAP_LGOPEN
|
||||
| NFS_CAP_ALLOCATE
|
||||
| NFS_CAP_COPY
|
||||
| NFS_CAP_OFFLOAD_CANCEL
|
||||
| NFS_CAP_DEALLOCATE
|
||||
| NFS_CAP_SEEK
|
||||
| NFS_CAP_LAYOUTSTATS
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl)
|
|||
static int nfs4_begin_drain_session(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_session *ses = clp->cl_session;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (clp->cl_slot_tbl)
|
||||
return nfs4_drain_slot_tbl(clp->cl_slot_tbl);
|
||||
|
|
@ -1525,6 +1525,7 @@ restart:
|
|||
default:
|
||||
pr_err("NFS: %s: unhandled error %d\n",
|
||||
__func__, status);
|
||||
/* Fall through */
|
||||
case -ENOMEM:
|
||||
case -NFS4ERR_DENIED:
|
||||
case -NFS4ERR_RECLAIM_BAD:
|
||||
|
|
@ -1588,6 +1589,22 @@ restart:
|
|||
}
|
||||
clear_bit(NFS_STATE_RECLAIM_NOGRACE,
|
||||
&state->flags);
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) {
|
||||
struct nfs4_copy_state *copy;
|
||||
|
||||
spin_lock(&sp->so_server->nfs_client->cl_lock);
|
||||
list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
|
||||
if (memcmp(&state->stateid.other, ©->parent_state->stateid.other, NFS4_STATEID_SIZE))
|
||||
continue;
|
||||
copy->flags = 1;
|
||||
complete(©->completion);
|
||||
printk("AGLO: server rebooted waking up the copy\n");
|
||||
break;
|
||||
}
|
||||
spin_unlock(&sp->so_server->nfs_client->cl_lock);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
nfs4_put_open_state(state);
|
||||
spin_lock(&sp->so_lock);
|
||||
goto restart;
|
||||
|
|
@ -1597,6 +1614,7 @@ restart:
|
|||
default:
|
||||
printk(KERN_ERR "NFS: %s: unhandled error %d\n",
|
||||
__func__, status);
|
||||
/* Fall through */
|
||||
case -ENOENT:
|
||||
case -ENOMEM:
|
||||
case -EACCES:
|
||||
|
|
@ -1608,6 +1626,7 @@ restart:
|
|||
break;
|
||||
case -EAGAIN:
|
||||
ssleep(1);
|
||||
/* Fall through */
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
|
|
@ -1939,7 +1958,9 @@ static int nfs4_establish_lease(struct nfs_client *clp)
|
|||
clp->cl_mvops->reboot_recovery_ops;
|
||||
int status;
|
||||
|
||||
nfs4_begin_drain_session(clp);
|
||||
status = nfs4_begin_drain_session(clp);
|
||||
if (status != 0)
|
||||
return status;
|
||||
cred = nfs4_get_clid_cred(clp);
|
||||
if (cred == NULL)
|
||||
return -ENOENT;
|
||||
|
|
@ -2027,7 +2048,9 @@ static int nfs4_try_migration(struct nfs_server *server, struct rpc_cred *cred)
|
|||
goto out;
|
||||
}
|
||||
|
||||
nfs4_begin_drain_session(clp);
|
||||
status = nfs4_begin_drain_session(clp);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = nfs4_replace_transport(server, locations);
|
||||
if (status != 0) {
|
||||
|
|
@ -2190,9 +2213,11 @@ again:
|
|||
case -ETIMEDOUT:
|
||||
if (clnt->cl_softrtry)
|
||||
break;
|
||||
/* Fall through */
|
||||
case -NFS4ERR_DELAY:
|
||||
case -EAGAIN:
|
||||
ssleep(1);
|
||||
/* Fall through */
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
dprintk("NFS: %s after status %d, retrying\n",
|
||||
__func__, status);
|
||||
|
|
@ -2204,6 +2229,7 @@ again:
|
|||
}
|
||||
if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX)
|
||||
break;
|
||||
/* Fall through */
|
||||
case -NFS4ERR_CLID_INUSE:
|
||||
case -NFS4ERR_WRONGSEC:
|
||||
/* No point in retrying if we already used RPC_AUTH_UNIX */
|
||||
|
|
@ -2374,7 +2400,9 @@ static int nfs4_reset_session(struct nfs_client *clp)
|
|||
|
||||
if (!nfs4_has_session(clp))
|
||||
return 0;
|
||||
nfs4_begin_drain_session(clp);
|
||||
status = nfs4_begin_drain_session(clp);
|
||||
if (status != 0)
|
||||
return status;
|
||||
cred = nfs4_get_clid_cred(clp);
|
||||
status = nfs4_proc_destroy_session(clp->cl_session, cred);
|
||||
switch (status) {
|
||||
|
|
@ -2417,7 +2445,9 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
|
|||
|
||||
if (!nfs4_has_session(clp))
|
||||
return 0;
|
||||
nfs4_begin_drain_session(clp);
|
||||
ret = nfs4_begin_drain_session(clp);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
cred = nfs4_get_clid_cred(clp);
|
||||
ret = nfs4_proc_bind_conn_to_session(clp, cred);
|
||||
if (cred)
|
||||
|
|
|
|||
|
|
@ -7789,6 +7789,7 @@ const struct rpc_procinfo nfs4_procedures[] = {
|
|||
PROC42(LAYOUTSTATS, enc_layoutstats, dec_layoutstats),
|
||||
PROC42(CLONE, enc_clone, dec_clone),
|
||||
PROC42(COPY, enc_copy, dec_copy),
|
||||
PROC42(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel),
|
||||
PROC(LOOKUPP, enc_lookupp, dec_lookupp),
|
||||
};
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue