upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / fs / nfsd / vfs.c
index 378ca30..26a87de 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/namei.h>
 #include <linux/vfs.h>
+#include <linux/delay.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #ifdef CONFIG_NFSD_V3
@@ -304,6 +305,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                 * we need to break all leases.
                 */
                err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
+               if (err == -EWOULDBLOCK)
+                       err = -ETIMEDOUT;
                if (err) /* ENOMEM or EWOULDBLOCK */
                        goto out_nfserr;
 
@@ -390,7 +393,7 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
        }
 out:
        kfree(buf);
-       return (error);
+       return error;
 }
 
 int
@@ -414,7 +417,10 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
                flags = NFS4_ACL_DIR;
 
        error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
-       if (error < 0)
+       if (error == -EINVAL) {
+               error = nfserr_attrnotsupp;
+               goto out;
+       } else if (error < 0)
                goto out_nfserr;
 
        if (pacl) {
@@ -664,12 +670,15 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
 
-       /* Disallow access to files with the append-only bit set or
-        * with mandatory locking enabled
+       /* Disallow write access to files with the append-only bit set
+        * or any access when mandatory locking enabled
         */
        err = nfserr_perm;
-       if (IS_APPEND(inode) || IS_ISMNDLK(inode))
+       if (IS_APPEND(inode) && (access & MAY_WRITE))
+               goto out;
+       if (IS_ISMNDLK(inode))
                goto out;
+
        if (!inode->i_fop)
                goto out;
 
@@ -678,6 +687,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
         * This may block while leases are broken.
         */
        err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
+       if (err == -EWOULDBLOCK)
+               err = -ETIMEDOUT;
        if (err) /* NOMEM or WOULDBLOCK */
                goto out_nfserr;
 
@@ -710,8 +721,8 @@ nfsd_close(struct file *filp)
  * As this calls fsync (not fdatasync) there is no need for a write_inode
  * after it.
  */
-inline void nfsd_dosync(struct file *filp, struct dentry *dp, 
-                       struct file_operations *fop)
+static inline void nfsd_dosync(struct file *filp, struct dentry *dp,
+                              struct file_operations *fop)
 {
        struct inode *inode = dp->d_inode;
        int (*fsync) (struct file *, struct dentry *, int);
@@ -723,7 +734,7 @@ inline void nfsd_dosync(struct file *filp, struct dentry *dp,
 }
        
 
-void
+static void
 nfsd_sync(struct file *filp)
 {
        struct inode *inode = filp->f_dentry->d_inode;
@@ -733,7 +744,7 @@ nfsd_sync(struct file *filp)
        up(&inode->i_sem);
 }
 
-void
+static void
 nfsd_sync_dir(struct dentry *dp)
 {
        nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
@@ -743,7 +754,7 @@ nfsd_sync_dir(struct dentry *dp)
  * Obtain the readahead parameters for the file
  * specified by (dev, ino).
  */
-static spinlock_t ra_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ra_lock);
 
 static inline struct raparms *
 nfsd_get_raparms(dev_t dev, ino_t ino)
@@ -813,30 +824,21 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
        return size;
 }
 
-/*
- * Read data from a file. count must contain the requested read count
- * on entry. On return, *count contains the number of bytes actually read.
- * N.B. After this call fhp needs an fh_put
- */
-int
-nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-          struct kvec *vec, int vlen, unsigned long *count)
+static inline int
+nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+              loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
+       struct inode *inode;
        struct raparms  *ra;
        mm_segment_t    oldfs;
        int             err;
-       struct file     *file;
-       struct inode    *inode;
 
-       err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
-       if (err)
-               goto out;
        err = nfserr_perm;
        inode = file->f_dentry->d_inode;
 #ifdef MSNFS
        if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
                (!lock_may_read(inode, offset, *count)))
-               goto out_close;
+               goto out;
 #endif
 
        /* Get readahead parameters */
@@ -872,41 +874,28 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                dnotify_parent(file->f_dentry, DN_ACCESS);
        } else 
                err = nfserrno(err);
-out_close:
-       nfsd_close(file);
 out:
        return err;
 }
 
-/*
- * Write data to a file.
- * The stable flag requests synchronous writes.
- * N.B. After this call fhp needs an fh_put
- */
-int
-nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-                               struct kvec *vec, int vlen,
+static inline int
+nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+                               loff_t offset, struct kvec *vec, int vlen,
                                unsigned long cnt, int *stablep)
 {
        struct svc_export       *exp;
-       struct file             *file;
        struct dentry           *dentry;
        struct inode            *inode;
        mm_segment_t            oldfs;
        int                     err = 0;
        int                     stable = *stablep;
 
-       err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
-       if (err)
-               goto out;
-       if (!cnt)
-               goto out_close;
        err = nfserr_perm;
 
 #ifdef MSNFS
        if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
                (!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
-               goto out_close;
+               goto out;
 #endif
 
        dentry = file->f_dentry;
@@ -971,8 +960,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                        if (atomic_read(&inode->i_writecount) > 1
                            || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) {
                                dprintk("nfsd: write defer %d\n", current->pid);
-                               set_current_state(TASK_UNINTERRUPTIBLE);
-                               schedule_timeout((HZ+99)/100);
+                               msleep(10);
                                dprintk("nfsd: write resume %d\n", current->pid);
                        }
 
@@ -993,12 +981,71 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                err = 0;
        else 
                err = nfserrno(err);
-out_close:
-       nfsd_close(file);
 out:
        return err;
 }
 
+/*
+ * Read data from a file. count must contain the requested read count
+ * on entry. On return, *count contains the number of bytes actually read.
+ * N.B. After this call fhp needs an fh_put
+ */
+int
+nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+               loff_t offset, struct kvec *vec, int vlen,
+               unsigned long *count)
+{
+       int             err;
+
+       if (file) {
+               err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+                               MAY_READ|MAY_OWNER_OVERRIDE);
+               if (err)
+                       goto out;
+               err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+       } else {
+               err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
+               if (err)
+                       goto out;
+               err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+               nfsd_close(file);
+       }
+out:
+       return err;
+}
+
+/*
+ * Write data to a file.
+ * The stable flag requests synchronous writes.
+ * N.B. After this call fhp needs an fh_put
+ */
+int
+nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+               loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
+               int *stablep)
+{
+       int                     err = 0;
+
+       if (file) {
+               err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+                               MAY_WRITE|MAY_OWNER_OVERRIDE);
+               if (err)
+                       goto out;
+               err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
+                               stablep);
+       } else {
+               err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
+               if (err)
+                       goto out;
+
+               if (cnt)
+                       err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
+                                            cnt, stablep);
+               nfsd_close(file);
+       }
+out:
+       return err;
+}
 
 #ifdef CONFIG_NFSD_V3
 /*