summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-27 23:45:22 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-27 23:45:22 +0000
commit5b35aa5cd29bb111d847b2a2ed18110acbfb1f44 (patch)
treec7bbaa1137528330d3c74d14056ef7016a52be72 /fs/nfsd/vfs.c
parent511bcd7c5924ce9e98ad1cb851988f7448dfef0f (diff)
Merge with Linux 2.3.24.
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c91
1 files changed, 48 insertions, 43 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index fa1753633..bc849dd8e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -234,6 +234,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
int ftype = 0;
int imode;
int err;
+ kernel_cap_t saved_cap = 0;
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
accmode |= MAY_WRITE;
@@ -242,7 +243,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
/* Get inode */
err = fh_verify(rqstp, fhp, ftype, accmode);
- if (err)
+ if (err || !iap->ia_valid)
goto out;
dentry = fhp->fh_dentry;
@@ -252,7 +253,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (err)
goto out_nfserr;
- /* The size case is special... */
+ /* The size case is special. It changes the file as well as the attributes. */
if (iap->ia_valid & ATTR_SIZE) {
if (!S_ISREG(inode->i_mode))
printk("nfsd_setattr: size change??\n");
@@ -264,15 +265,14 @@ printk("nfsd_setattr: size change??\n");
err = get_write_access(inode);
if (err)
goto out_nfserr;
- /* N.B. Should we update the inode cache here? */
- inode->i_size = iap->ia_size;
- if (inode->i_op && inode->i_op->truncate)
- inode->i_op->truncate(inode);
- mark_inode_dirty(inode);
- put_write_access(inode);
- iap->ia_valid &= ~ATTR_SIZE;
- iap->ia_valid |= ATTR_MTIME;
- iap->ia_mtime = CURRENT_TIME;
+
+ err = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
+ iap->ia_size<inode->i_size ? iap->ia_size : inode->i_size,
+ abs(inode->i_size - iap->ia_size));
+
+ if (err)
+ goto out_nfserr;
+ DQUOT_INIT(inode);
}
imode = inode->i_mode;
@@ -294,23 +294,32 @@ printk("nfsd_setattr: size change??\n");
}
/* Change the attributes. */
- if (iap->ia_valid) {
- kernel_cap_t saved_cap = 0;
- iap->ia_valid |= ATTR_CTIME;
- iap->ia_ctime = CURRENT_TIME;
- if (current->fsuid != 0) {
- saved_cap = current->cap_effective;
- cap_clear(current->cap_effective);
- }
+
+ iap->ia_valid |= ATTR_CTIME;
+ if (current->fsuid != 0) {
+ saved_cap = current->cap_effective;
+ cap_clear(current->cap_effective);
+ }
+ if (iap->ia_valid & ATTR_SIZE) {
+ fh_lock(fhp);
err = notify_change(dentry, iap);
- if (current->fsuid != 0)
- current->cap_effective = saved_cap;
- if (err)
- goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export))
- write_inode_now(inode);
+ if (!err) {
+ vmtruncate(inode,iap->ia_size);
+ if (inode->i_op && inode->i_op->truncate)
+ inode->i_op->truncate(inode);
+ }
+ fh_unlock(fhp);
+ put_write_access(inode);
}
+ else
+ err = notify_change(dentry, iap);
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;
+ if (err)
+ goto out_nfserr;
+ if (EX_ISSYNC(fhp->fh_export))
+ write_inode_now(inode);
err = 0;
out:
return err;
@@ -401,7 +410,6 @@ nfsd_close(struct file *filp)
filp->f_op->release(inode, filp);
if (filp->f_mode & FMODE_WRITE) {
put_write_access(inode);
- DQUOT_DROP(inode);
}
}
@@ -548,7 +556,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
file.f_flags |= O_SYNC;
- fh_lock(fhp); /* lock inode */
file.f_pos = offset; /* set write offset */
/* Write the data. */
@@ -580,8 +587,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
current->cap_effective = saved_cap;
}
- fh_unlock(fhp); /* unlock inode */
-
if (err >= 0 && stable) {
static unsigned long last_ino = 0;
static kdev_t last_dev = NODEV;
@@ -651,9 +656,13 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = nfserr_perm;
if (!flen)
goto out;
- err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
- if (err)
- goto out;
+
+ /* from mkdir it won't be verified, from create it will */
+ if (!fhp->fh_dverified) {
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+ if (err)
+ goto out;
+ }
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
@@ -731,7 +740,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
DQUOT_INIT(dirp);
err = opfunc(dirp, dchild, iap->ia_mode, rdev);
- DQUOT_DROP(dirp);
if (err < 0)
goto out_nfserr;
@@ -786,6 +794,11 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
err = get_write_access(inode);
if (err)
goto out_nfserr;
+ err = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
+ size<inode->i_size ? size : inode->i_size,
+ abs(inode->i_size - size));
+ if (err)
+ goto out_nfserr;
/* Things look sane, lock and do it. */
fh_lock(fhp);
@@ -797,15 +810,14 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
cap_clear(current->cap_effective);
}
err = notify_change(dentry, &newattrs);
- if (current->fsuid != 0)
- current->cap_effective = saved_cap;
if (!err) {
vmtruncate(inode, size);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
}
+ if (current->fsuid != 0)
+ current->cap_effective = saved_cap;
put_write_access(inode);
- DQUOT_DROP(inode);
fh_unlock(fhp);
out_nfserr:
if (err)
@@ -902,7 +914,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!dnew->d_inode) {
DQUOT_INIT(dirp);
err = dirp->i_op->symlink(dirp, dnew, path);
- DQUOT_DROP(dirp);
if (!err) {
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
@@ -981,7 +992,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
DQUOT_INIT(dirp);
err = dirp->i_op->link(dold, dirp, dnew);
- DQUOT_DROP(dirp);
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
write_inode_now(dirp);
@@ -1105,8 +1115,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
}
} else
dprintk("nfsd: Caught race in nfsd_rename");
- DQUOT_DROP(fdir);
- DQUOT_DROP(tdir);
nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
dput(ndentry);
@@ -1157,7 +1165,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
goto out;
}
- expire_by_dentry(rdentry);
if (type != S_IFDIR) {
/* It's UNLINK */
@@ -1168,7 +1175,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = vfs_unlink(dirp, rdentry);
- DQUOT_DROP(dirp);
fh_unlock(fhp);
dput(rdentry);
@@ -1188,7 +1194,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = vfs_rmdir(dirp, rdentry);
rdentry->d_count--;
- DQUOT_DROP(dirp);
if (!fhp->fh_post_version)
fhp->fh_post_version = dirp->i_version;
fhp->fh_locked = 0;