Commit a18093af authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-6.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd fixes from Chuck Lever:

 - Fix a number of crashers

 - Update email address for an NFSD reviewer

* tag 'nfsd-6.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  fs/nfsd: fix update of inode attrs in CB_GETATTR
  nfsd: fix potential UAF in nfsd4_cb_getattr_release
  nfsd: hold reference to delegation when updating it for cb_getattr
  MAINTAINERS: Update Olga Kornievskaia's email address
  nfsd: prevent panic for nfsv4.0 closed files in nfs4_show_open
  nfsd: ensure that nfsd4_fattr_args.context is zeroed out
parents 28405268 7e8ae848
...@@ -12167,7 +12167,7 @@ KERNEL NFSD, SUNRPC, AND LOCKD SERVERS ...@@ -12167,7 +12167,7 @@ KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
M: Chuck Lever <chuck.lever@oracle.com> M: Chuck Lever <chuck.lever@oracle.com>
M: Jeff Layton <jlayton@kernel.org> M: Jeff Layton <jlayton@kernel.org>
R: Neil Brown <neilb@suse.de> R: Neil Brown <neilb@suse.de>
R: Olga Kornievskaia <kolga@netapp.com> R: Olga Kornievskaia <okorniev@redhat.com>
R: Dai Ngo <Dai.Ngo@oracle.com> R: Dai Ngo <Dai.Ngo@oracle.com>
R: Tom Talpey <tom@talpey.com> R: Tom Talpey <tom@talpey.com>
L: linux-nfs@vger.kernel.org L: linux-nfs@vger.kernel.org
......
...@@ -487,9 +487,17 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry, ...@@ -487,9 +487,17 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
error = security_inode_setattr(idmap, dentry, attr); error = security_inode_setattr(idmap, dentry, attr);
if (error) if (error)
return error; return error;
/*
* If ATTR_DELEG is set, then these attributes are being set on
* behalf of the holder of a write delegation. We want to avoid
* breaking the delegation in this case.
*/
if (!(ia_valid & ATTR_DELEG)) {
error = try_break_deleg(inode, delegated_inode); error = try_break_deleg(inode, delegated_inode);
if (error) if (error)
return error; return error;
}
if (inode->i_op->setattr) if (inode->i_op->setattr)
error = inode->i_op->setattr(idmap, dentry, attr); error = inode->i_op->setattr(idmap, dentry, attr);
......
...@@ -2789,6 +2789,7 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) ...@@ -2789,6 +2789,7 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", deny & NFS4_SHARE_ACCESS_READ ? "r" : "-",
deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-");
if (nf) {
spin_lock(&nf->fi_lock); spin_lock(&nf->fi_lock);
file = find_any_file_locked(nf); file = find_any_file_locked(nf);
if (file) { if (file) {
...@@ -2798,6 +2799,8 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) ...@@ -2798,6 +2799,8 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
seq_puts(s, ", "); seq_puts(s, ", ");
} }
spin_unlock(&nf->fi_lock); spin_unlock(&nf->fi_lock);
} else
seq_puts(s, "closed, ");
nfs4_show_owner(s, oo); nfs4_show_owner(s, oo);
if (st->sc_status & SC_STATUS_ADMIN_REVOKED) if (st->sc_status & SC_STATUS_ADMIN_REVOKED)
seq_puts(s, ", admin-revoked"); seq_puts(s, ", admin-revoked");
...@@ -3075,9 +3078,9 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb) ...@@ -3075,9 +3078,9 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb)
struct nfs4_delegation *dp = struct nfs4_delegation *dp =
container_of(ncf, struct nfs4_delegation, dl_cb_fattr); container_of(ncf, struct nfs4_delegation, dl_cb_fattr);
nfs4_put_stid(&dp->dl_stid);
clear_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags); clear_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags);
wake_up_bit(&ncf->ncf_cb_flags, CB_GETATTR_BUSY); wake_up_bit(&ncf->ncf_cb_flags, CB_GETATTR_BUSY);
nfs4_put_stid(&dp->dl_stid);
} }
static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = { static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
...@@ -8812,7 +8815,7 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, ...@@ -8812,7 +8815,7 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
/** /**
* nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict * nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict
* @rqstp: RPC transaction context * @rqstp: RPC transaction context
* @inode: file to be checked for a conflict * @dentry: dentry of inode to be checked for a conflict
* @modified: return true if file was modified * @modified: return true if file was modified
* @size: new size of file if modified is true * @size: new size of file if modified is true
* *
...@@ -8827,16 +8830,16 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, ...@@ -8827,16 +8830,16 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
* code is returned. * code is returned.
*/ */
__be32 __be32
nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
bool *modified, u64 *size) bool *modified, u64 *size)
{ {
__be32 status; __be32 status;
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lease *fl; struct file_lease *fl;
struct nfs4_delegation *dp;
struct iattr attrs; struct iattr attrs;
struct nfs4_cb_fattr *ncf; struct nfs4_cb_fattr *ncf;
struct inode *inode = d_inode(dentry);
*modified = false; *modified = false;
ctx = locks_inode_context(inode); ctx = locks_inode_context(inode);
...@@ -8859,7 +8862,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8859,7 +8862,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
goto break_lease; goto break_lease;
} }
if (type == F_WRLCK) { if (type == F_WRLCK) {
dp = fl->c.flc_owner; struct nfs4_delegation *dp = fl->c.flc_owner;
if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) { if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);
return 0; return 0;
...@@ -8867,6 +8871,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8867,6 +8871,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
break_lease: break_lease:
nfsd_stats_wdeleg_getattr_inc(nn); nfsd_stats_wdeleg_getattr_inc(nn);
dp = fl->c.flc_owner; dp = fl->c.flc_owner;
refcount_inc(&dp->dl_stid.sc_count);
ncf = &dp->dl_cb_fattr; ncf = &dp->dl_cb_fattr;
nfs4_cb_getattr(&dp->dl_cb_fattr); nfs4_cb_getattr(&dp->dl_cb_fattr);
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);
...@@ -8876,27 +8881,37 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8876,27 +8881,37 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
/* Recall delegation only if client didn't respond */ /* Recall delegation only if client didn't respond */
status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
if (status != nfserr_jukebox || if (status != nfserr_jukebox ||
!nfsd_wait_for_delegreturn(rqstp, inode)) !nfsd_wait_for_delegreturn(rqstp, inode)) {
nfs4_put_stid(&dp->dl_stid);
return status; return status;
} }
}
if (!ncf->ncf_file_modified && if (!ncf->ncf_file_modified &&
(ncf->ncf_initial_cinfo != ncf->ncf_cb_change || (ncf->ncf_initial_cinfo != ncf->ncf_cb_change ||
ncf->ncf_cur_fsize != ncf->ncf_cb_fsize)) ncf->ncf_cur_fsize != ncf->ncf_cb_fsize))
ncf->ncf_file_modified = true; ncf->ncf_file_modified = true;
if (ncf->ncf_file_modified) { if (ncf->ncf_file_modified) {
int err;
/* /*
* Per section 10.4.3 of RFC 8881, the server would * Per section 10.4.3 of RFC 8881, the server would
* not update the file's metadata with the client's * not update the file's metadata with the client's
* modified size * modified size
*/ */
attrs.ia_mtime = attrs.ia_ctime = current_time(inode); attrs.ia_mtime = attrs.ia_ctime = current_time(inode);
attrs.ia_valid = ATTR_MTIME | ATTR_CTIME; attrs.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_DELEG;
setattr_copy(&nop_mnt_idmap, inode, &attrs); inode_lock(inode);
mark_inode_dirty(inode); err = notify_change(&nop_mnt_idmap, dentry, &attrs, NULL);
inode_unlock(inode);
if (err) {
nfs4_put_stid(&dp->dl_stid);
return nfserrno(err);
}
ncf->ncf_cur_fsize = ncf->ncf_cb_fsize; ncf->ncf_cur_fsize = ncf->ncf_cb_fsize;
*size = ncf->ncf_cur_fsize; *size = ncf->ncf_cur_fsize;
*modified = true; *modified = true;
} }
nfs4_put_stid(&dp->dl_stid);
return 0; return 0;
} }
break; break;
......
...@@ -3545,6 +3545,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -3545,6 +3545,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args.dentry = dentry; args.dentry = dentry;
args.ignore_crossmnt = (ignore_crossmnt != 0); args.ignore_crossmnt = (ignore_crossmnt != 0);
args.acl = NULL; args.acl = NULL;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
args.context = NULL;
#endif
/* /*
* Make a local copy of the attribute bitmap that can be modified. * Make a local copy of the attribute bitmap that can be modified.
...@@ -3562,7 +3565,7 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -3562,7 +3565,7 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
} }
args.size = 0; args.size = 0;
if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) { if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry), status = nfsd4_deleg_getattr_conflict(rqstp, dentry,
&file_modified, &size); &file_modified, &size);
if (status) if (status)
goto out; goto out;
...@@ -3617,7 +3620,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -3617,7 +3620,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args.contextsupport = false; args.contextsupport = false;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
args.context = NULL;
if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) || if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
if (exp->ex_flags & NFSEXP_SECURITY_LABEL) if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
......
...@@ -781,5 +781,5 @@ static inline bool try_to_expire_client(struct nfs4_client *clp) ...@@ -781,5 +781,5 @@ static inline bool try_to_expire_client(struct nfs4_client *clp)
} }
extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp,
struct inode *inode, bool *file_modified, u64 *size); struct dentry *dentry, bool *file_modified, u64 *size);
#endif /* NFSD4_STATE_H */ #endif /* NFSD4_STATE_H */
...@@ -210,6 +210,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, ...@@ -210,6 +210,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
#define ATTR_TIMES_SET (1 << 16) #define ATTR_TIMES_SET (1 << 16)
#define ATTR_TOUCH (1 << 17) #define ATTR_TOUCH (1 << 17)
#define ATTR_DELEG (1 << 18) /* Delegated attrs. Don't break write delegations */
/* /*
* Whiteout is represented by a char device. The following constants define the * Whiteout is represented by a char device. The following constants define the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment