[media] coda: rename prescan_failed to hold and stop stream after timeout
[cascardo/linux.git] / fs / nfsd / vfs.c
index 16f0673..140c496 100644 (file)
@@ -820,55 +820,54 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
        return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
 }
 
-static __be32
-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)
+__be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
 {
-       mm_segment_t    oldfs;
-       __be32          err;
-       int             host_err;
-
-       err = nfserr_perm;
-
-       if (file->f_op->splice_read && rqstp->rq_splice_ok) {
-               struct splice_desc sd = {
-                       .len            = 0,
-                       .total_len      = *count,
-                       .pos            = offset,
-                       .u.data         = rqstp,
-               };
-
-               rqstp->rq_next_page = rqstp->rq_respages + 1;
-               host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
-       } else {
-               oldfs = get_fs();
-               set_fs(KERNEL_DS);
-               host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
-               set_fs(oldfs);
-       }
-
        if (host_err >= 0) {
                nfsdstats.io_read += host_err;
                *count = host_err;
-               err = 0;
                fsnotify_access(file);
+               return 0;
        } else 
-               err = nfserrno(host_err);
-       return err;
+               return nfserrno(host_err);
+}
+
+int nfsd_splice_read(struct svc_rqst *rqstp,
+                    struct file *file, loff_t offset, unsigned long *count)
+{
+       struct splice_desc sd = {
+               .len            = 0,
+               .total_len      = *count,
+               .pos            = offset,
+               .u.data         = rqstp,
+       };
+       int host_err;
+
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
+       host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
+       return nfsd_finish_read(file, count, host_err);
 }
 
-static void kill_suid(struct dentry *dentry)
+int nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
+               unsigned long *count)
 {
-       struct iattr    ia;
-       ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
+       mm_segment_t oldfs;
+       int host_err;
 
-       mutex_lock(&dentry->d_inode->i_mutex);
-       /*
-        * Note we call this on write, so notify_change will not
-        * encounter any conflicting delegations:
-        */
-       notify_change(dentry, &ia, NULL);
-       mutex_unlock(&dentry->d_inode->i_mutex);
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
+       set_fs(oldfs);
+       return nfsd_finish_read(file, count, host_err);
+}
+
+static __be32
+nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
+             loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+{
+       if (file->f_op->splice_read && rqstp->rq_splice_ok)
+               return nfsd_splice_read(rqstp, file, offset, count);
+       else
+               return nfsd_readv(file, offset, vec, vlen, count);
 }
 
 /*
@@ -922,6 +921,16 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        int                     stable = *stablep;
        int                     use_wgather;
        loff_t                  pos = offset;
+       unsigned int            pflags = current->flags;
+
+       if (rqstp->rq_local)
+               /*
+                * We want less throttling in balance_dirty_pages()
+                * and shrink_inactive_list() so that nfs to
+                * localhost doesn't cause nfsd to lock up due to all
+                * the client's dirty pages or its congested queue.
+                */
+               current->flags |= PF_LESS_THROTTLE;
 
        dentry = file->f_path.dentry;
        inode = dentry->d_inode;
@@ -942,10 +951,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        nfsdstats.io_write += host_err;
        fsnotify_modify(file);
 
-       /* clear setuid/setgid flag after write */
-       if (inode->i_mode & (S_ISUID | S_ISGID))
-               kill_suid(dentry);
-
        if (stable) {
                if (use_wgather)
                        host_err = wait_for_concurrent_writes(file);
@@ -959,36 +964,33 @@ out_nfserr:
                err = 0;
        else
                err = nfserrno(host_err);
+       if (rqstp->rq_local)
+               tsk_restore_flags(current, pflags, PF_LESS_THROTTLE);
        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
- */
-__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
-       loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+__be32 nfsd_get_tmp_read_open(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct file **file, struct raparms **ra)
 {
-       struct file *file;
        struct inode *inode;
-       struct raparms  *ra;
        __be32 err;
 
-       err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+       err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, file);
        if (err)
                return err;
 
-       inode = file_inode(file);
+       inode = file_inode(*file);
 
        /* Get readahead parameters */
-       ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
+       *ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
 
-       if (ra && ra->p_set)
-               file->f_ra = ra->p_ra;
-
-       err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+       if (*ra && (*ra)->p_set)
+               (*file)->f_ra = (*ra)->p_ra;
+       return nfs_ok;
+}
 
+void nfsd_put_tmp_read_open(struct file *file, struct raparms *ra)
+{
        /* Write back readahead params */
        if (ra) {
                struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
@@ -998,28 +1000,29 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
                ra->p_count--;
                spin_unlock(&rab->pb_lock);
        }
-
        nfsd_close(file);
-       return err;
 }
 
-/* As above, but use the provided file descriptor. */
-__be32
-nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
-               loff_t offset, struct kvec *vec, int vlen,
-               unsigned long *count)
+/*
+ * 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
+ */
+__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+       loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
-       __be32          err;
+       struct file *file;
+       struct raparms  *ra;
+       __be32 err;
+
+       err = nfsd_get_tmp_read_open(rqstp, fhp, &file, &ra);
+       if (err)
+               return err;
+
+       err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
+
+       nfsd_put_tmp_read_open(file, ra);
 
-       if (file) {
-               err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
-                               NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE);
-               if (err)
-                       goto out;
-               err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
-       } else /* Note file may still be NULL in NFSv4 special stateid case: */
-               err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
-out:
        return err;
 }