Loading fs/nfsd/vfs.c +84 −60 Original line number Diff line number Diff line Loading @@ -298,41 +298,12 @@ 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. */ __be32 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int check_guard, time_t guardtime) static void nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) { struct dentry *dentry; struct inode *inode; int accmode = NFSD_MAY_SATTR; umode_t ftype = 0; __be32 err; int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) goto out; /* * NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which Loading @@ -342,8 +313,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * 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. * 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) Loading @@ -370,30 +340,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, } } /* * The size case is special. * It changes the file as well as 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; 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; Loading @@ -415,8 +361,86 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); } } } /* Change the attributes. */ 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, int check_guard, time_t guardtime) { struct dentry *dentry; struct inode *inode; int accmode = NFSD_MAY_SATTR; umode_t ftype = 0; __be32 err; int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) goto out; nfsd_sanitize_attrs(inode, iap); /* * The size case is special, it changes the file in addition to the * attributes. */ if (iap->ia_valid & ATTR_SIZE) { err = nfsd_get_write_access(rqstp, fhp, iap); if (err) goto out; size_change = 1; } iap->ia_valid |= ATTR_CTIME; Loading Loading
fs/nfsd/vfs.c +84 −60 Original line number Diff line number Diff line Loading @@ -298,41 +298,12 @@ 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. */ __be32 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int check_guard, time_t guardtime) static void nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) { struct dentry *dentry; struct inode *inode; int accmode = NFSD_MAY_SATTR; umode_t ftype = 0; __be32 err; int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) goto out; /* * NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which Loading @@ -342,8 +313,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * 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. * 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) Loading @@ -370,30 +340,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, } } /* * The size case is special. * It changes the file as well as 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; 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; Loading @@ -415,8 +361,86 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); } } } /* Change the attributes. */ 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, int check_guard, time_t guardtime) { struct dentry *dentry; struct inode *inode; int accmode = NFSD_MAY_SATTR; umode_t ftype = 0; __be32 err; int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) goto out; nfsd_sanitize_attrs(inode, iap); /* * The size case is special, it changes the file in addition to the * attributes. */ if (iap->ia_valid & ATTR_SIZE) { err = nfsd_get_write_access(rqstp, fhp, iap); if (err) goto out; size_change = 1; } iap->ia_valid |= ATTR_CTIME; Loading