Change nfsd_sync_dir to return an error if ->sync fails, and pass that error
up through the stack. This involves a number of rearrangements of error
paths, and care to distinguish between Linux -errno numbers and NFSERR
numbers.
In the 'create' routines, we continue with the 'setattr' even if a previous
sync_dir failed.
This patch is quite different from Takashi's in a few ways, but there is still
a strong lineage.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
- filemap_fdatawrite(inode->i_mapping);
- if (fop && (fsync = fop->fsync))
- err=fsync(filp, dp, 0);
- filemap_fdatawait(inode->i_mapping);
+ err = filemap_fdatawrite(inode->i_mapping);
+ if (err == 0 && fop && (fsync = fop->fsync))
+ err = fsync(filp, dp, 0);
+ if (err == 0)
+ err = filemap_fdatawait(inode->i_mapping);
nfsd_sync_dir(struct dentry *dp)
{
nfsd_sync_dir(struct dentry *dp)
{
- nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
+ return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
if (EX_ISSYNC(fhp->fh_export)) {
if (file->f_op && file->f_op->fsync) {
err = nfsd_sync(file);
if (EX_ISSYNC(fhp->fh_export)) {
if (file->f_op && file->f_op->fsync) {
err = nfsd_sync(file);
} else {
err = nfserr_notsupp;
}
} else {
err = nfserr_notsupp;
}
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
+ err = nfsd_sync_dir(dentry);
write_inode_now(dchild->d_inode, 1);
}
write_inode_now(dchild->d_inode, 1);
}
* send along the gid when it tries to implement setgid
* directories via NFS.
*/
* send along the gid when it tries to implement setgid
* directories via NFS.
*/
- err = 0;
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
- err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+ int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = err2;
+ }
/*
* Update the file handle to get the new inode info.
*/
/*
* Update the file handle to get the new inode info.
*/
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
+ err = nfsd_sync_dir(dentry);
+ if (err)
+ err = nfserrno(err);
/* setattr will sync the child (or not) */
}
/* setattr will sync the child (or not) */
}
- /*
- * Update the filehandle to get the new inode info.
- */
- err = fh_update(resfhp);
- if (err)
- goto out;
-
if (createmode == NFS3_CREATE_EXCLUSIVE) {
/* Cram the verifier into atime/mtime/mode */
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
if (createmode == NFS3_CREATE_EXCLUSIVE) {
/* Cram the verifier into atime/mtime/mode */
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
* implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
* implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
- err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) {
+ int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = nfserrno(err2);
+ }
+
+ /*
+ * Update the filehandle to get the new inode info.
+ */
+ if (!err)
+ err = fh_update(resfhp);
} else
err = vfs_symlink(dentry->d_inode, dnew, path, mode);
} else
err = vfs_symlink(dentry->d_inode, dnew, path, mode);
if (EX_ISSYNC(fhp->fh_export))
if (EX_ISSYNC(fhp->fh_export))
- nfsd_sync_dir(dentry);
- } else
+ err = nfsd_sync_dir(dentry);
+ if (err)
err = nfserrno(err);
fh_unlock(fhp);
err = nfserrno(err);
fh_unlock(fhp);
err = vfs_link(dold, dirp, dnew);
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
err = vfs_link(dold, dirp, dnew);
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
+ err = nfsd_sync_dir(ddir);
write_inode_now(dest, 1);
write_inode_now(dest, 1);
+ if (err)
+ err = nfserrno(err);
}
} else {
if (err == -EXDEV && rqstp->rq_vers == 2)
}
} else {
if (err == -EXDEV && rqstp->rq_vers == 2)
#endif
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
#endif
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
- nfsd_sync_dir(tdentry);
- nfsd_sync_dir(fdentry);
+ err = nfsd_sync_dir(tdentry);
+ if (!err)
+ err = nfsd_sync_dir(fdentry);
- if (err)
- goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export))
- nfsd_sync_dir(dentry);
-
-out:
- return err;
+ if (err == 0 &&
+ EX_ISSYNC(fhp->fh_export))
+ err = nfsd_sync_dir(dentry);
out_nfserr:
err = nfserrno(err);
out_nfserr:
err = nfserrno(err);
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
-void nfsd_sync_dir(struct dentry *dp);
+int nfsd_sync_dir(struct dentry *dp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL