Updated from Linux LTS 3.10.20 to 3.10.21
This commit is contained in:
@@ -56,10 +56,19 @@ static void configfs_d_iput(struct dentry * dentry,
|
||||
struct configfs_dirent *sd = dentry->d_fsdata;
|
||||
|
||||
if (sd) {
|
||||
BUG_ON(sd->s_dentry != dentry);
|
||||
/* Coordinate with configfs_readdir */
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
sd->s_dentry = NULL;
|
||||
/* Coordinate with configfs_attach_attr where will increase
|
||||
* sd->s_count and update sd->s_dentry to new allocated one.
|
||||
* Only set sd->dentry to null when this dentry is the only
|
||||
* sd owner.
|
||||
* If not do so, configfs_d_iput may run just after
|
||||
* configfs_attach_attr and set sd->s_dentry to null
|
||||
* even it's still in use.
|
||||
*/
|
||||
if (atomic_read(&sd->s_count) <= 2)
|
||||
sd->s_dentry = NULL;
|
||||
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
configfs_put(sd);
|
||||
}
|
||||
@@ -426,8 +435,11 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
|
||||
struct configfs_attribute * attr = sd->s_element;
|
||||
int error;
|
||||
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
dentry->d_fsdata = configfs_get(sd);
|
||||
sd->s_dentry = dentry;
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
|
||||
error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG,
|
||||
configfs_init_file);
|
||||
if (error) {
|
||||
|
||||
@@ -1671,6 +1671,12 @@ int __get_dumpable(unsigned long mm_flags)
|
||||
return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns the actual value of the suid_dumpable flag. For things
|
||||
* that are using this for checking for privilege transitions, it must
|
||||
* test against SUID_DUMP_USER rather than treating it as a boolean
|
||||
* value.
|
||||
*/
|
||||
int get_dumpable(struct mm_struct *mm)
|
||||
{
|
||||
return __get_dumpable(mm->flags);
|
||||
|
||||
@@ -1160,29 +1160,24 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
|
||||
int ret;
|
||||
|
||||
if (!data->rpc_done) {
|
||||
ret = data->rpc_status;
|
||||
goto err;
|
||||
if (data->rpc_status) {
|
||||
ret = data->rpc_status;
|
||||
goto err;
|
||||
}
|
||||
/* cached opens have already been processed */
|
||||
goto update;
|
||||
}
|
||||
|
||||
ret = -ESTALE;
|
||||
if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
|
||||
!(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
|
||||
!(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
|
||||
goto err;
|
||||
|
||||
ret = -ENOMEM;
|
||||
state = nfs4_get_open_state(inode, data->owner);
|
||||
if (state == NULL)
|
||||
goto err;
|
||||
|
||||
ret = nfs_refresh_inode(inode, &data->f_attr);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (data->o_res.delegation_type != 0)
|
||||
nfs4_opendata_check_deleg(data, state);
|
||||
update:
|
||||
update_open_stateid(state, &data->o_res.stateid, NULL,
|
||||
data->o_arg.fmode);
|
||||
atomic_inc(&state->count);
|
||||
|
||||
return state;
|
||||
err:
|
||||
@@ -4572,6 +4567,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
|
||||
status = 0;
|
||||
}
|
||||
request->fl_ops->fl_release_private(request);
|
||||
request->fl_ops = NULL;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
if (err)
|
||||
goto out3;
|
||||
exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
|
||||
if (!uid_valid(exp.ex_anon_uid))
|
||||
goto out3;
|
||||
|
||||
/* anon gid */
|
||||
err = get_int(&mesg, &an_int);
|
||||
if (err)
|
||||
goto out3;
|
||||
exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
|
||||
if (!gid_valid(exp.ex_anon_gid))
|
||||
goto out3;
|
||||
|
||||
/* fsid */
|
||||
err = get_int(&mesg, &an_int);
|
||||
@@ -583,6 +579,17 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
exp.ex_uuid);
|
||||
if (err)
|
||||
goto out4;
|
||||
/*
|
||||
* For some reason exportfs has been passing down an
|
||||
* invalid (-1) uid & gid on the "dummy" export which it
|
||||
* uses to test export support. To make sure exportfs
|
||||
* sees errors from check_export we therefore need to
|
||||
* delay these checks till after check_export:
|
||||
*/
|
||||
if (!uid_valid(exp.ex_anon_uid))
|
||||
goto out4;
|
||||
if (!gid_valid(exp.ex_anon_gid))
|
||||
goto out4;
|
||||
}
|
||||
|
||||
expp = svc_export_lookup(&exp);
|
||||
|
||||
215
fs/nfsd/vfs.c
215
fs/nfsd/vfs.c
@@ -297,8 +297,104 @@ commit_metadata(struct svc_fh *fhp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Set various file attributes.
|
||||
* N.B. After this call fhp needs an fh_put
|
||||
* Go over the attributes and take care of the small differences between
|
||||
* NFS semantics and what Linux expects.
|
||||
*/
|
||||
static void
|
||||
nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
|
||||
{
|
||||
/*
|
||||
* NFSv2 does not differentiate between "set-[ac]time-to-now"
|
||||
* which only requires access, and "set-[ac]time-to-X" which
|
||||
* requires ownership.
|
||||
* So if it looks like it might be "set both to the same time which
|
||||
* is close to now", and if inode_change_ok fails, then we
|
||||
* convert to "set to now" instead of "set to explicit time"
|
||||
*
|
||||
* We only call inode_change_ok as the last test as technically
|
||||
* it is not an interface that we should be using.
|
||||
*/
|
||||
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
|
||||
#define MAX_TOUCH_TIME_ERROR (30*60)
|
||||
if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
|
||||
iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
|
||||
/*
|
||||
* Looks probable.
|
||||
*
|
||||
* Now just make sure time is in the right ballpark.
|
||||
* Solaris, at least, doesn't seem to care what the time
|
||||
* request is. We require it be within 30 minutes of now.
|
||||
*/
|
||||
time_t delta = iap->ia_atime.tv_sec - get_seconds();
|
||||
if (delta < 0)
|
||||
delta = -delta;
|
||||
if (delta < MAX_TOUCH_TIME_ERROR &&
|
||||
inode_change_ok(inode, iap) != 0) {
|
||||
/*
|
||||
* Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
|
||||
* This will cause notify_change to set these times
|
||||
* to "now"
|
||||
*/
|
||||
iap->ia_valid &= ~BOTH_TIME_SET;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanitize the mode change */
|
||||
if (iap->ia_valid & ATTR_MODE) {
|
||||
iap->ia_mode &= S_IALLUGO;
|
||||
iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
|
||||
}
|
||||
|
||||
/* Revoke setuid/setgid on chown */
|
||||
if (!S_ISDIR(inode->i_mode) &&
|
||||
(((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) ||
|
||||
((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) {
|
||||
iap->ia_valid |= ATTR_KILL_PRIV;
|
||||
if (iap->ia_valid & ATTR_MODE) {
|
||||
/* we're setting mode too, just clear the s*id bits */
|
||||
iap->ia_mode &= ~S_ISUID;
|
||||
if (iap->ia_mode & S_IXGRP)
|
||||
iap->ia_mode &= ~S_ISGID;
|
||||
} else {
|
||||
/* set ATTR_KILL_* bits and let VFS handle it */
|
||||
iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct iattr *iap)
|
||||
{
|
||||
struct inode *inode = fhp->fh_dentry->d_inode;
|
||||
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.
|
||||
*/
|
||||
__be32
|
||||
nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||
@@ -332,114 +428,43 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||
if (!iap->ia_valid)
|
||||
goto out;
|
||||
|
||||
nfsd_sanitize_attrs(inode, iap);
|
||||
|
||||
/*
|
||||
* NFSv2 does not differentiate between "set-[ac]time-to-now"
|
||||
* which only requires access, and "set-[ac]time-to-X" which
|
||||
* requires ownership.
|
||||
* So if it looks like it might be "set both to the same time which
|
||||
* is close to now", and if inode_change_ok fails, then we
|
||||
* convert to "set to now" instead of "set to explicit time"
|
||||
*
|
||||
* We only call inode_change_ok as the last test as technically
|
||||
* it is not an interface that we should be using. It is only
|
||||
* valid if the filesystem does not define it's own i_op->setattr.
|
||||
*/
|
||||
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
|
||||
#define MAX_TOUCH_TIME_ERROR (30*60)
|
||||
if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
|
||||
iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
|
||||
/*
|
||||
* Looks probable.
|
||||
*
|
||||
* Now just make sure time is in the right ballpark.
|
||||
* Solaris, at least, doesn't seem to care what the time
|
||||
* request is. We require it be within 30 minutes of now.
|
||||
*/
|
||||
time_t delta = iap->ia_atime.tv_sec - get_seconds();
|
||||
if (delta < 0)
|
||||
delta = -delta;
|
||||
if (delta < MAX_TOUCH_TIME_ERROR &&
|
||||
inode_change_ok(inode, iap) != 0) {
|
||||
/*
|
||||
* Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
|
||||
* This will cause notify_change to set these times
|
||||
* to "now"
|
||||
*/
|
||||
iap->ia_valid &= ~BOTH_TIME_SET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The size case is special.
|
||||
* It changes the file as well as the attributes.
|
||||
* The size case is special, it changes the file in addition to the
|
||||
* attributes.
|
||||
*/
|
||||
if (iap->ia_valid & ATTR_SIZE) {
|
||||
if (iap->ia_size < inode->i_size) {
|
||||
err = nfsd_permission(rqstp, fhp->fh_export, dentry,
|
||||
NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
host_err = get_write_access(inode);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
err = nfsd_get_write_access(rqstp, fhp, iap);
|
||||
if (err)
|
||||
goto out;
|
||||
size_change = 1;
|
||||
host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
|
||||
if (host_err) {
|
||||
put_write_access(inode);
|
||||
goto out_nfserr;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanitize the mode change */
|
||||
if (iap->ia_valid & ATTR_MODE) {
|
||||
iap->ia_mode &= S_IALLUGO;
|
||||
iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
|
||||
}
|
||||
|
||||
/* Revoke setuid/setgid on chown */
|
||||
if (!S_ISDIR(inode->i_mode) &&
|
||||
(((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) ||
|
||||
((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) {
|
||||
iap->ia_valid |= ATTR_KILL_PRIV;
|
||||
if (iap->ia_valid & ATTR_MODE) {
|
||||
/* we're setting mode too, just clear the s*id bits */
|
||||
iap->ia_mode &= ~S_ISUID;
|
||||
if (iap->ia_mode & S_IXGRP)
|
||||
iap->ia_mode &= ~S_ISGID;
|
||||
} else {
|
||||
/* set ATTR_KILL_* bits and let VFS handle it */
|
||||
iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
|
||||
}
|
||||
}
|
||||
|
||||
/* Change the attributes. */
|
||||
|
||||
iap->ia_valid |= ATTR_CTIME;
|
||||
|
||||
err = nfserr_notsync;
|
||||
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
|
||||
host_err = nfsd_break_lease(inode);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
fh_lock(fhp);
|
||||
|
||||
host_err = notify_change(dentry, iap);
|
||||
err = nfserrno(host_err);
|
||||
fh_unlock(fhp);
|
||||
if (check_guard && guardtime != inode->i_ctime.tv_sec) {
|
||||
err = nfserr_notsync;
|
||||
goto out_put_write_access;
|
||||
}
|
||||
|
||||
host_err = nfsd_break_lease(inode);
|
||||
if (host_err)
|
||||
goto out_put_write_access_nfserror;
|
||||
|
||||
fh_lock(fhp);
|
||||
host_err = notify_change(dentry, iap);
|
||||
fh_unlock(fhp);
|
||||
|
||||
out_put_write_access_nfserror:
|
||||
err = nfserrno(host_err);
|
||||
out_put_write_access:
|
||||
if (size_change)
|
||||
put_write_access(inode);
|
||||
if (!err)
|
||||
commit_metadata(fhp);
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_nfserr:
|
||||
err = nfserrno(host_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || \
|
||||
|
||||
Reference in New Issue
Block a user