patch-2.2.14 linux/fs/nfsd/vfs.c
Next file: linux/fs/ntfs/inode.c
Previous file: linux/fs/nfsd/stats.c
Back to the patch index
Back to the overall index
- Lines: 200
- Date:
Tue Jan 4 10:12:23 2000
- Orig file:
v2.2.13/linux/fs/nfsd/vfs.c
- Orig date:
Tue Jan 4 11:10:40 2000
diff -u --recursive --new-file v2.2.13/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
@@ -21,7 +21,6 @@
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <linux/ext2_fs.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
@@ -48,9 +47,15 @@
/* Hack until we have a macro check for mandatory locks. */
#ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i) (((i)->i_mode & (S_ISGID|S_IXGRP)) == S_ISGID)
+#define IS_ISMNDLK(i) (((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
+ == (S_ISGID|S_IFREG))
#endif
+/* Time difference margin in seconds for comparison. It is a
+ dynamically-tunable parameter via /proc/fs/nfs/time-diff-margin.
+ */
+extern long nfsd_time_diff_margin;
+
/* Check for dir entries '.' and '..' */
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
@@ -236,8 +241,30 @@
inode = dentry->d_inode;
err = inode_change_ok(inode, iap);
- if (err)
+ if (err) {
+ /* It is very tricky. When you are not the file owner,
+ but have the write permission, you should be allowed
+ to set atime and mtime to the current time on the
+ server. However, the NFS V2 protocol doesn't support
+ it. It has been fixed in V3. Here we do this: if the
+ current server time and atime/mtime are close enough,
+ we use the current server time. */
+#define CURRENT_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
+ if (iap->ia_mtime == iap->ia_atime
+ && ((iap->ia_valid & (CURRENT_TIME_SET))
+ == CURRENT_TIME_SET)) {
+ time_t now = CURRENT_TIME;
+ time_t delta = iap->ia_atime - now;
+ if (delta < 0) delta = -delta;
+ if (delta <= nfsd_time_diff_margin) {
+ iap->ia_valid &= ~CURRENT_TIME_SET;
+ goto current_time_ok;
+ }
+ }
goto out_nfserr;
+ }
+
+current_time_ok:
/* The size case is special... */
if (iap->ia_valid & ATTR_SIZE) {
@@ -248,15 +275,19 @@
if (err)
goto out;
}
+ DQUOT_INIT(inode);
err = get_write_access(inode);
- if (err)
+ if (err) {
+ DQUOT_DROP(inode);
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);
+ DQUOT_DROP(inode);
iap->ia_valid &= ~ATTR_SIZE;
iap->ia_valid |= ATTR_MTIME;
iap->ia_mtime = CURRENT_TIME;
@@ -554,7 +585,7 @@
/* clear setuid/setgid flag after write */
if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
struct iattr ia;
- kernel_cap_t saved_cap;
+ kernel_cap_t saved_cap = 0;
ia.ia_valid = ATTR_MODE;
ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
@@ -658,10 +689,6 @@
if (IS_ERR(dchild))
goto out_nfserr;
fh_compose(resfhp, fhp->fh_export, dchild);
- /* Lock the parent and check for errors ... */
- err = fh_lock_parent(fhp, dchild);
- if (err)
- goto out;
} else {
dchild = resfhp->fh_dentry;
if (!fhp->fh_locked)
@@ -670,6 +697,15 @@
dentry->d_parent->d_name.name,
dentry->d_name.name);
}
+ err = nfserr_exist;
+ if (dchild->d_inode)
+ goto out;
+ if (!fhp->fh_locked) {
+ /* Lock the parent and check for errors ... */
+ err = fh_lock_parent(fhp, dchild);
+ if (err)
+ goto out;
+ }
/*
* Make sure the child dentry is still negative ...
*/
@@ -695,8 +731,7 @@
case S_IFCHR:
case S_IFBLK:
/* The client is _NOT_ required to do security enforcement */
- if(!capable(CAP_SYS_ADMIN))
- {
+ if(!capable(CAP_SYS_ADMIN)) {
err = -EPERM;
goto out;
}
@@ -759,7 +794,7 @@
struct inode *inode;
struct iattr newattrs;
int err;
- kernel_cap_t saved_cap;
+ kernel_cap_t saved_cap = 0;
err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
if (err)
@@ -899,6 +934,7 @@
/* Compose the fh so the dentry will be freed ... */
out_compose:
fh_compose(resfhp, fhp->fh_export, dnew);
+
out:
return err;
@@ -1091,6 +1127,15 @@
DQUOT_DROP(tdir);
nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
+
+ if (!err && odentry->d_inode) {
+ add_to_rename_cache(tdir->i_ino,
+ odentry->d_inode->i_dev,
+ fdir->i_ino,
+ odentry->d_inode->i_ino);
+ } else {
+ printk(": no inode in rename or err: %d.\n", err);
+ }
dput(ndentry);
out_dput_old:
@@ -1132,7 +1177,6 @@
err = PTR_ERR(rdentry);
if (IS_ERR(rdentry))
goto out_nfserr;
-
if (!rdentry->d_inode) {
dput(rdentry);
err = nfserr_noent;
@@ -1154,7 +1198,7 @@
fh_unlock(fhp);
dput(rdentry);
-
+ expire_by_dentry(rdentry);
} else {
/* It's RMDIR */
/* See comments in fs/namei.c:do_rmdir */
@@ -1183,6 +1227,7 @@
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
+
out:
return err;
@@ -1314,7 +1359,7 @@
{
struct inode *inode = dentry->d_inode;
int err;
- kernel_cap_t saved_cap;
+ kernel_cap_t saved_cap = 0;
if (acc == MAY_NOP)
return 0;
@@ -1334,7 +1379,7 @@
inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
#endif
#ifndef CONFIG_NFSD_SUN
- if (dentry->d_mounts != dentry) {
+ if (dentry->d_mounts != dentry) {
return nfserr_perm;
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)