mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
Three more miscellaneous nfsd bugfixes.
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYk5bGAAoJECebzXlCjuG+vGcP/j2Sw74vbJX4ifkFQvUomOp/ 83IHinaax5RDIqryf903iabvKX1SuXpVuxgpxtaSCz+oS9fV5wv/28NdIrMwfICJ DC3I2xQ/osLUGHw1Td8BZ+Fv+P0Th+OGKwWCydp3Xejg/X+XUKrLs/Ex1/rHwTzJ y/BIAV7BU94HlDFxif7sKbv6mi/gpETlvJK4AAbSbvpd4f5JuBXPQBtJBxUPtwi1 zM0pQzMoBgY5XzAZBWmQEYCJjTje5wqiueDHtteh8/X7FoLWtAcHsOmleglleKQn 927eRCTrHt9ioToyZJM4GkH8eW/nOMpaKKvjXCTdoKsuEZyAnlPk0VZUAikfDvql dr9FznI21Geq/c9IeU3+1xSbe1I9eDO0L9qWp8prUikIZwI4kdEBN5z/0oMMcU4q IXw2lb46w8JD11GIIAGZIhZb63FdO75Ck4Z2GX6UUFqt246s26Go9yJIZEDfu5sL 8FLmwgOYNMhFrSPAR9JmnBors5gNT9owNwieUB8IFvgMv1ajz2CWG2yvNO9Sq/SK a/HJJ7A1YvX0uSzsKsvO/j5S4cY73l2kWKX4NRqMFXIYzMzNGHvIvIB238tXAzZe Z5YaMycsjuRKe9VkP2lZQtVzl9qfnvkd5o6Tg3RkMZXkVOHMB/j2yratWB2XTl3h I2xAGjQFJ/Pn66pJWNe0 =yQ4e -----END PGP SIGNATURE----- Merge tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux Pull nfsd fixes from Bruce Fields: "Three more miscellaneous nfsd bugfixes" * tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux: svcrpc: fix oops in absence of krb5 module nfsd: special case truncates some more NFSD: Fix a null reference case in find_or_create_lock_stateid()
This commit is contained in:
commit
1fc576b82b
5 changed files with 51 additions and 76 deletions
|
@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||||
struct nfs4_layout_stateid *ls;
|
struct nfs4_layout_stateid *ls;
|
||||||
struct nfs4_stid *stp;
|
struct nfs4_stid *stp;
|
||||||
|
|
||||||
stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache);
|
stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
|
||||||
|
nfsd4_free_layout_stateid);
|
||||||
if (!stp)
|
if (!stp)
|
||||||
return NULL;
|
return NULL;
|
||||||
stp->sc_free = nfsd4_free_layout_stateid;
|
|
||||||
get_nfs4_file(fp);
|
get_nfs4_file(fp);
|
||||||
stp->sc_file = fp;
|
stp->sc_file = fp;
|
||||||
|
|
||||||
|
|
|
@ -633,8 +633,8 @@ out:
|
||||||
return co;
|
return co;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
|
||||||
struct kmem_cache *slab)
|
void (*sc_free)(struct nfs4_stid *))
|
||||||
{
|
{
|
||||||
struct nfs4_stid *stid;
|
struct nfs4_stid *stid;
|
||||||
int new_id;
|
int new_id;
|
||||||
|
@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
||||||
idr_preload_end();
|
idr_preload_end();
|
||||||
if (new_id < 0)
|
if (new_id < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
|
stid->sc_free = sc_free;
|
||||||
stid->sc_client = cl;
|
stid->sc_client = cl;
|
||||||
stid->sc_stateid.si_opaque.so_id = new_id;
|
stid->sc_stateid.si_opaque.so_id = new_id;
|
||||||
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
|
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
|
||||||
|
@ -675,15 +677,12 @@ out_free:
|
||||||
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
|
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
|
||||||
{
|
{
|
||||||
struct nfs4_stid *stid;
|
struct nfs4_stid *stid;
|
||||||
struct nfs4_ol_stateid *stp;
|
|
||||||
|
|
||||||
stid = nfs4_alloc_stid(clp, stateid_slab);
|
stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
|
||||||
if (!stid)
|
if (!stid)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
stp = openlockstateid(stid);
|
return openlockstateid(stid);
|
||||||
stp->st_stid.sc_free = nfs4_free_ol_stateid;
|
|
||||||
return stp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs4_free_deleg(struct nfs4_stid *stid)
|
static void nfs4_free_deleg(struct nfs4_stid *stid)
|
||||||
|
@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
|
||||||
goto out_dec;
|
goto out_dec;
|
||||||
if (delegation_blocked(¤t_fh->fh_handle))
|
if (delegation_blocked(¤t_fh->fh_handle))
|
||||||
goto out_dec;
|
goto out_dec;
|
||||||
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
|
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
|
||||||
if (dp == NULL)
|
if (dp == NULL)
|
||||||
goto out_dec;
|
goto out_dec;
|
||||||
|
|
||||||
dp->dl_stid.sc_free = nfs4_free_deleg;
|
|
||||||
/*
|
/*
|
||||||
* delegation seqid's are never incremented. The 4.1 special
|
* delegation seqid's are never incremented. The 4.1 special
|
||||||
* meaning of seqid 0 isn't meaningful, really, but let's avoid
|
* meaning of seqid 0 isn't meaningful, really, but let's avoid
|
||||||
|
@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
|
||||||
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
|
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
|
||||||
get_nfs4_file(fp);
|
get_nfs4_file(fp);
|
||||||
stp->st_stid.sc_file = fp;
|
stp->st_stid.sc_file = fp;
|
||||||
stp->st_stid.sc_free = nfs4_free_lock_stateid;
|
|
||||||
stp->st_access_bmap = 0;
|
stp->st_access_bmap = 0;
|
||||||
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
||||||
stp->st_openstp = open_stp;
|
stp->st_openstp = open_stp;
|
||||||
|
@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
|
||||||
lst = find_lock_stateid(lo, fi);
|
lst = find_lock_stateid(lo, fi);
|
||||||
if (lst == NULL) {
|
if (lst == NULL) {
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
ns = nfs4_alloc_stid(clp, stateid_slab);
|
ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
|
||||||
if (ns == NULL)
|
if (ns == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
|
||||||
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
|
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
|
||||||
stateid_t *stateid, unsigned char typemask,
|
stateid_t *stateid, unsigned char typemask,
|
||||||
struct nfs4_stid **s, struct nfsd_net *nn);
|
struct nfs4_stid **s, struct nfsd_net *nn);
|
||||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
|
||||||
struct kmem_cache *slab);
|
void (*sc_free)(struct nfs4_stid *));
|
||||||
void nfs4_unhash_stid(struct nfs4_stid *s);
|
void nfs4_unhash_stid(struct nfs4_stid *s);
|
||||||
void nfs4_put_stid(struct nfs4_stid *s);
|
void nfs4_put_stid(struct nfs4_stid *s);
|
||||||
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
|
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
|
||||||
|
|
|
@ -332,37 +332,6 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static __be32
|
|
||||||
nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|
||||||
struct iattr *iap)
|
|
||||||
{
|
|
||||||
struct inode *inode = d_inode(fhp->fh_dentry);
|
|
||||||
int host_err;
|
|
||||||
|
|
||||||
if (iap->ia_size < inode->i_size) {
|
|
||||||
__be32 err;
|
|
||||||
|
|
||||||
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
|
|
||||||
NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
host_err = get_write_access(inode);
|
|
||||||
if (host_err)
|
|
||||||
goto out_nfserrno;
|
|
||||||
|
|
||||||
host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
|
|
||||||
if (host_err)
|
|
||||||
goto out_put_write_access;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_put_write_access:
|
|
||||||
put_write_access(inode);
|
|
||||||
out_nfserrno:
|
|
||||||
return nfserrno(host_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set various file attributes. After this call fhp needs an fh_put.
|
* Set various file attributes. After this call fhp needs an fh_put.
|
||||||
*/
|
*/
|
||||||
|
@ -377,7 +346,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||||
__be32 err;
|
__be32 err;
|
||||||
int host_err;
|
int host_err;
|
||||||
bool get_write_count;
|
bool get_write_count;
|
||||||
int size_change = 0;
|
|
||||||
|
|
||||||
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
|
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
|
||||||
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
|
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
|
||||||
|
@ -390,11 +358,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||||
/* Get inode */
|
/* Get inode */
|
||||||
err = fh_verify(rqstp, fhp, ftype, accmode);
|
err = fh_verify(rqstp, fhp, ftype, accmode);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
return err;
|
||||||
if (get_write_count) {
|
if (get_write_count) {
|
||||||
host_err = fh_want_write(fhp);
|
host_err = fh_want_write(fhp);
|
||||||
if (host_err)
|
if (host_err)
|
||||||
return nfserrno(host_err);
|
goto out_host_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dentry = fhp->fh_dentry;
|
dentry = fhp->fh_dentry;
|
||||||
|
@ -405,50 +373,59 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||||
iap->ia_valid &= ~ATTR_MODE;
|
iap->ia_valid &= ~ATTR_MODE;
|
||||||
|
|
||||||
if (!iap->ia_valid)
|
if (!iap->ia_valid)
|
||||||
goto out;
|
return 0;
|
||||||
|
|
||||||
nfsd_sanitize_attrs(inode, iap);
|
nfsd_sanitize_attrs(inode, iap);
|
||||||
|
|
||||||
|
if (check_guard && guardtime != inode->i_ctime.tv_sec)
|
||||||
|
return nfserr_notsync;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The size case is special, it changes the file in addition to the
|
* The size case is special, it changes the file in addition to the
|
||||||
* attributes.
|
* attributes, and file systems don't expect it to be mixed with
|
||||||
|
* "random" attribute changes. We thus split out the size change
|
||||||
|
* into a separate call for vfs_truncate, and do the rest as a
|
||||||
|
* a separate setattr call.
|
||||||
*/
|
*/
|
||||||
if (iap->ia_valid & ATTR_SIZE) {
|
if (iap->ia_valid & ATTR_SIZE) {
|
||||||
err = nfsd_get_write_access(rqstp, fhp, iap);
|
struct path path = {
|
||||||
if (err)
|
.mnt = fhp->fh_export->ex_path.mnt,
|
||||||
goto out;
|
.dentry = dentry,
|
||||||
size_change = 1;
|
};
|
||||||
|
bool implicit_mtime = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RFC5661, Section 18.30.4:
|
* vfs_truncate implicity updates the mtime IFF the file size
|
||||||
* Changing the size of a file with SETATTR indirectly
|
* actually changes. Avoid the additional seattr call below if
|
||||||
* changes the time_modify and change attributes.
|
* the only other attribute that the client sends is the mtime.
|
||||||
*
|
|
||||||
* (and similar for the older RFCs)
|
|
||||||
*/
|
*/
|
||||||
if (iap->ia_size != i_size_read(inode))
|
if (iap->ia_size != i_size_read(inode) &&
|
||||||
iap->ia_valid |= ATTR_MTIME;
|
((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
|
||||||
|
implicit_mtime = true;
|
||||||
|
|
||||||
|
host_err = vfs_truncate(&path, iap->ia_size);
|
||||||
|
if (host_err)
|
||||||
|
goto out_host_err;
|
||||||
|
|
||||||
|
iap->ia_valid &= ~ATTR_SIZE;
|
||||||
|
if (implicit_mtime)
|
||||||
|
iap->ia_valid &= ~ATTR_MTIME;
|
||||||
|
if (!iap->ia_valid)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
iap->ia_valid |= ATTR_CTIME;
|
iap->ia_valid |= ATTR_CTIME;
|
||||||
|
|
||||||
if (check_guard && guardtime != inode->i_ctime.tv_sec) {
|
|
||||||
err = nfserr_notsync;
|
|
||||||
goto out_put_write_access;
|
|
||||||
}
|
|
||||||
|
|
||||||
fh_lock(fhp);
|
fh_lock(fhp);
|
||||||
host_err = notify_change(dentry, iap, NULL);
|
host_err = notify_change(dentry, iap, NULL);
|
||||||
fh_unlock(fhp);
|
fh_unlock(fhp);
|
||||||
err = nfserrno(host_err);
|
if (host_err)
|
||||||
|
goto out_host_err;
|
||||||
|
|
||||||
out_put_write_access:
|
done:
|
||||||
if (size_change)
|
host_err = commit_metadata(fhp);
|
||||||
put_write_access(inode);
|
out_host_err:
|
||||||
if (!err)
|
return nfserrno(host_err);
|
||||||
err = nfserrno(commit_metadata(fhp));
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_NFSD_V4)
|
#if defined(CONFIG_NFSD_V4)
|
||||||
|
|
|
@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,
|
||||||
if (!oa->data)
|
if (!oa->data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
|
creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
|
||||||
if (!creds) {
|
if (!creds) {
|
||||||
kfree(oa->data);
|
kfree(oa->data);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue