Merge branch 'for-3.19' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 23:25:31 +0000 (15:25 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 23:25:31 +0000 (15:25 -0800)
Pull nfsd updates from Bruce Fields:
 "A comparatively quieter cycle for nfsd this time, but still with two
  larger changes:

   - RPC server scalability improvements from Jeff Layton (using RCU
     instead of a spinlock to find idle threads).

   - server-side NFSv4.2 ALLOCATE/DEALLOCATE support from Anna
     Schumaker, enabling fallocate on new clients"

* 'for-3.19' of git://linux-nfs.org/~bfields/linux: (32 commits)
  nfsd4: fix xdr4 count of server in fs_location4
  nfsd4: fix xdr4 inclusion of escaped char
  sunrpc/cache: convert to use string_escape_str()
  sunrpc: only call test_bit once in svc_xprt_received
  fs: nfsd: Fix signedness bug in compare_blob
  sunrpc: add some tracepoints around enqueue and dequeue of svc_xprt
  sunrpc: convert to lockless lookup of queued server threads
  sunrpc: fix potential races in pool_stats collection
  sunrpc: add a rcu_head to svc_rqst and use kfree_rcu to free it
  sunrpc: require svc_create callers to pass in meaningful shutdown routine
  sunrpc: have svc_wake_up only deal with pool 0
  sunrpc: convert sp_task_pending flag to use atomic bitops
  sunrpc: move rq_cachetype field to better optimize space
  sunrpc: move rq_splice_ok flag into rq_flags
  sunrpc: move rq_dropme flag into rq_flags
  sunrpc: move rq_usedeferral flag to rq_flags
  sunrpc: move rq_local field to rq_flags
  sunrpc: add a generic rq_flags field to svc_rqst and move rq_secure to it
  nfsd: minor off by one checks in __write_versions()
  sunrpc: release svc_pool_map reference when serv allocation fails
  ...

1  2 
drivers/staging/android/ashmem.c
fs/ioctl.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/open.c
include/linux/fs.h

@@@ -418,7 -418,7 +418,7 @@@ out
  }
  
  /*
 - * ashmem_shrink - our cache shrinker, called from mm/vmscan.c :: shrink_slab
 + * ashmem_shrink - our cache shrinker, called from mm/vmscan.c
   *
   * 'nr_to_scan' is the number of objects to scan for freeing.
   *
@@@ -446,7 -446,7 +446,7 @@@ ashmem_shrink_scan(struct shrinker *shr
                loff_t start = range->pgstart * PAGE_SIZE;
                loff_t end = (range->pgend + 1) * PAGE_SIZE;
  
-               do_fallocate(range->asma->file,
+               vfs_fallocate(range->asma->file,
                                FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                start, end - start);
                range->purged = ASHMEM_WAS_PURGED;
@@@ -785,6 -785,7 +785,6 @@@ static long ashmem_ioctl(struct file *f
                                .nr_to_scan = LONG_MAX,
                        };
                        ret = ashmem_shrink_count(&ashmem_shrinker, &sc);
 -                      nodes_setall(sc.nodes_to_scan);
                        ashmem_shrink_scan(&ashmem_shrinker, &sc);
                }
                break;
diff --combined fs/ioctl.c
@@@ -443,7 -443,7 +443,7 @@@ int ioctl_preallocate(struct file *filp
                return -EINVAL;
        }
  
-       return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+       return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
  }
  
  static int file_ioctl(struct file *filp, unsigned int cmd,
@@@ -518,12 -518,10 +518,12 @@@ static int ioctl_fsfreeze(struct file *
                return -EPERM;
  
        /* If filesystem doesn't support freeze feature, return. */
 -      if (sb->s_op->freeze_fs == NULL)
 +      if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
                return -EOPNOTSUPP;
  
        /* Freeze */
 +      if (sb->s_op->freeze_super)
 +              return sb->s_op->freeze_super(sb);
        return freeze_super(sb);
  }
  
@@@ -535,8 -533,6 +535,8 @@@ static int ioctl_fsthaw(struct file *fi
                return -EPERM;
  
        /* Thaw */
 +      if (sb->s_op->thaw_super)
 +              return sb->s_op->thaw_super(sb);
        return thaw_super(sb);
  }
  
diff --combined fs/nfsd/nfs4state.c
@@@ -41,7 -41,7 +41,7 @@@
  #include <linux/ratelimit.h>
  #include <linux/sunrpc/svcauth_gss.h>
  #include <linux/sunrpc/addr.h>
 -#include <linux/hash.h>
 +#include <linux/jhash.h>
  #include "xdr4.h"
  #include "xdr4cb.h"
  #include "vfs.h"
@@@ -275,9 -275,11 +275,11 @@@ opaque_hashval(const void *ptr, int nby
        return x;
  }
  
- static void nfsd4_free_file(struct nfs4_file *f)
+ static void nfsd4_free_file_rcu(struct rcu_head *rcu)
  {
-       kmem_cache_free(file_slab, f);
+       struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu);
+       kmem_cache_free(file_slab, fp);
  }
  
  static inline void
@@@ -286,9 -288,10 +288,10 @@@ put_nfs4_file(struct nfs4_file *fi
        might_lock(&state_lock);
  
        if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
-               hlist_del(&fi->fi_hash);
+               hlist_del_rcu(&fi->fi_hash);
                spin_unlock(&state_lock);
-               nfsd4_free_file(fi);
+               WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
+               call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
        }
  }
  
@@@ -594,7 -597,7 +597,7 @@@ static int delegation_blocked(struct kn
                }
                spin_unlock(&blocked_delegations_lock);
        }
 -      hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
 +      hash = jhash(&fh->fh_base, fh->fh_size, 0);
        if (test_bit(hash&255, bd->set[0]) &&
            test_bit((hash>>8)&255, bd->set[0]) &&
            test_bit((hash>>16)&255, bd->set[0]))
@@@ -613,7 -616,7 +616,7 @@@ static void block_delegations(struct kn
        u32 hash;
        struct bloom_pair *bd = &blocked_delegations;
  
 -      hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
 +      hash = jhash(&fh->fh_base, fh->fh_size, 0);
  
        spin_lock(&blocked_delegations_lock);
        __set_bit(hash&255, bd->set[bd->new]);
@@@ -1440,7 -1443,7 +1443,7 @@@ static void init_session(struct svc_rqs
        list_add(&new->se_perclnt, &clp->cl_sessions);
        spin_unlock(&clp->cl_lock);
  
-       if (cses->flags & SESSION4_BACK_CHAN) {
+       {
                struct sockaddr *sa = svc_addr(rqstp);
                /*
                 * This is a little silly; with sessions there's no real
@@@ -1711,15 -1714,14 +1714,14 @@@ static int copy_cred(struct svc_cred *t
        return 0;
  }
  
- static long long
+ static int
  compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
  {
-       long long res;
-       res = o1->len - o2->len;
-       if (res)
-               return res;
-       return (long long)memcmp(o1->data, o2->data, o1->len);
+       if (o1->len < o2->len)
+               return -1;
+       if (o1->len > o2->len)
+               return 1;
+       return memcmp(o1->data, o2->data, o1->len);
  }
  
  static int same_name(const char *n1, const char *n2)
@@@ -1907,7 -1909,7 +1909,7 @@@ add_clp_to_name_tree(struct nfs4_clien
  static struct nfs4_client *
  find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
  {
-       long long cmp;
+       int cmp;
        struct rb_node *node = root->rb_node;
        struct nfs4_client *clp;
  
@@@ -3057,10 -3059,9 +3059,9 @@@ static struct nfs4_file *nfsd4_alloc_fi
  }
  
  /* OPEN Share state helper functions */
- static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
+ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
+                               struct nfs4_file *fp)
  {
-       unsigned int hashval = file_hashval(fh);
        lockdep_assert_held(&state_lock);
  
        atomic_set(&fp->fi_ref, 1);
        fp->fi_share_deny = 0;
        memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
        memset(fp->fi_access, 0, sizeof(fp->fi_access));
-       hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
+       hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
  }
  
  void
@@@ -3294,17 -3295,14 +3295,14 @@@ move_to_close_lru(struct nfs4_ol_statei
  
  /* search file_hashtbl[] for file */
  static struct nfs4_file *
- find_file_locked(struct knfsd_fh *fh)
+ find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
  {
-       unsigned int hashval = file_hashval(fh);
        struct nfs4_file *fp;
  
-       lockdep_assert_held(&state_lock);
-       hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
+       hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
                if (nfsd_fh_match(&fp->fi_fhandle, fh)) {
-                       get_nfs4_file(fp);
-                       return fp;
+                       if (atomic_inc_not_zero(&fp->fi_ref))
+                               return fp;
                }
        }
        return NULL;
@@@ -3314,10 -3312,11 +3312,11 @@@ static struct nfs4_file 
  find_file(struct knfsd_fh *fh)
  {
        struct nfs4_file *fp;
+       unsigned int hashval = file_hashval(fh);
  
-       spin_lock(&state_lock);
-       fp = find_file_locked(fh);
-       spin_unlock(&state_lock);
+       rcu_read_lock();
+       fp = find_file_locked(fh, hashval);
+       rcu_read_unlock();
        return fp;
  }
  
@@@ -3325,11 -3324,18 +3324,18 @@@ static struct nfs4_file 
  find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
  {
        struct nfs4_file *fp;
+       unsigned int hashval = file_hashval(fh);
+       rcu_read_lock();
+       fp = find_file_locked(fh, hashval);
+       rcu_read_unlock();
+       if (fp)
+               return fp;
  
        spin_lock(&state_lock);
-       fp = find_file_locked(fh);
-       if (fp == NULL) {
-               nfsd4_init_file(new, fh);
+       fp = find_file_locked(fh, hashval);
+       if (likely(fp == NULL)) {
+               nfsd4_init_file(fh, hashval, new);
                fp = new;
        }
        spin_unlock(&state_lock);
@@@ -4127,7 -4133,7 +4133,7 @@@ void nfsd4_cleanup_open_state(struct nf
                nfs4_put_stateowner(so);
        }
        if (open->op_file)
-               nfsd4_free_file(open->op_file);
+               kmem_cache_free(file_slab, open->op_file);
        if (open->op_stp)
                nfs4_put_stid(&open->op_stp->st_stid);
  }
diff --combined fs/nfsd/nfs4xdr.c
@@@ -1513,6 -1513,23 +1513,23 @@@ static __be32 nfsd4_decode_reclaim_comp
        DECODE_TAIL;
  }
  
+ static __be32
+ nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
+                      struct nfsd4_fallocate *fallocate)
+ {
+       DECODE_HEAD;
+       status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid);
+       if (status)
+               return status;
+       READ_BUF(16);
+       p = xdr_decode_hyper(p, &fallocate->falloc_offset);
+       xdr_decode_hyper(p, &fallocate->falloc_length);
+       DECODE_TAIL;
+ }
  static __be32
  nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
  {
@@@ -1604,10 -1621,10 +1621,10 @@@ static nfsd4_dec nfsd4_dec_ops[] = 
        [OP_RECLAIM_COMPLETE]   = (nfsd4_dec)nfsd4_decode_reclaim_complete,
  
        /* new operations for NFSv4.2 */
-       [OP_ALLOCATE]           = (nfsd4_dec)nfsd4_decode_notsupp,
+       [OP_ALLOCATE]           = (nfsd4_dec)nfsd4_decode_fallocate,
        [OP_COPY]               = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_COPY_NOTIFY]        = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_DEALLOCATE]         = (nfsd4_dec)nfsd4_decode_notsupp,
+       [OP_DEALLOCATE]         = (nfsd4_dec)nfsd4_decode_fallocate,
        [OP_IO_ADVISE]          = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_LAYOUTERROR]        = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_LAYOUTSTATS]        = (nfsd4_dec)nfsd4_decode_notsupp,
@@@ -1714,7 -1731,7 +1731,7 @@@ nfsd4_decode_compound(struct nfsd4_comp
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
  
        if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
-               argp->rqstp->rq_splice_ok = false;
+               clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
  
        DECODE_TAIL;
  }
@@@ -1795,9 -1812,12 +1812,12 @@@ static __be32 nfsd4_encode_components_e
                }
                else
                        end++;
+               if (found_esc)
+                       end = next;
                str = end;
        }
-       pathlen = htonl(xdr->buf->len - pathlen_offset);
+       pathlen = htonl(count);
        write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
        return 0;
  }
@@@ -1886,7 -1906,7 +1906,7 @@@ static __be32 nfsd4_encode_path(struct 
                        goto out_free;
                }
                p = xdr_encode_opaque(p, dentry->d_name.name, len);
 -              dprintk("/%s", dentry->d_name.name);
 +              dprintk("/%pd", dentry);
                spin_unlock(&dentry->d_lock);
                dput(dentry);
                ncomponents--;
@@@ -3236,10 -3256,10 +3256,10 @@@ nfsd4_encode_read(struct nfsd4_compound
  
        p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
        if (!p) {
-               WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
+               WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
                return nfserr_resource;
        }
-       if (resp->xdr.buf->page_len && resp->rqstp->rq_splice_ok) {
+       if (resp->xdr.buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
                WARN_ON_ONCE(1);
                return nfserr_resource;
        }
                        goto err_truncate;
        }
  
-       if (file->f_op->splice_read && resp->rqstp->rq_splice_ok)
+       if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
                err = nfsd4_encode_splice_read(resp, read, file, maxcount);
        else
                err = nfsd4_encode_readv(resp, read, file, maxcount);
diff --combined fs/nfsd/nfsctl.c
@@@ -231,10 -231,6 +231,10 @@@ static struct file_operations reply_cac
   * payload - write methods
   */
  
 +static inline struct net *netns(struct file *file)
 +{
 +      return file_inode(file)->i_sb->s_fs_info;
 +}
  
  /**
   * write_unlock_ip - Release all locks used by a client
@@@ -256,7 -252,7 +256,7 @@@ static ssize_t write_unlock_ip(struct f
        struct sockaddr *sap = (struct sockaddr *)&address;
        size_t salen = sizeof(address);
        char *fo_path;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 +      struct net *net = netns(file);
  
        /* sanity check */
        if (size == 0)
@@@ -354,6 -350,7 +354,6 @@@ static ssize_t write_filehandle(struct 
        int len;
        struct auth_domain *dom;
        struct knfsd_fh fh;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        if (size == 0)
                return -EINVAL;
        if (!dom)
                return -ENOMEM;
  
 -      len = exp_rootfh(net, dom, path, &fh,  maxsize);
 +      len = exp_rootfh(netns(file), dom, path, &fh,  maxsize);
        auth_domain_put(dom);
        if (len)
                return len;
@@@ -432,7 -429,7 +432,7 @@@ static ssize_t write_threads(struct fil
  {
        char *mesg = buf;
        int rv;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 +      struct net *net = netns(file);
  
        if (size > 0) {
                int newthreads;
@@@ -483,7 -480,7 +483,7 @@@ static ssize_t write_pool_threads(struc
        int len;
        int npools;
        int *nthreads;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 +      struct net *net = netns(file);
  
        mutex_lock(&nfsd_mutex);
        npools = nfsd_nrpools(net);
@@@ -546,7 -543,8 +546,7 @@@ static ssize_t __write_versions(struct 
        unsigned minor;
        ssize_t tlen = 0;
        char *sep;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
  
        if (size>0) {
                if (nn->nfsd_serv)
                                       num);
                        sep = " ";
  
-                       if (len > remaining)
+                       if (len >= remaining)
                                break;
                        remaining -= len;
                        buf += len;
                                                '+' : '-',
                                        minor);
  
-                       if (len > remaining)
+                       if (len >= remaining)
                                break;
                        remaining -= len;
                        buf += len;
                }
  
        len = snprintf(buf, remaining, "\n");
-       if (len > remaining)
+       if (len >= remaining)
                return -EINVAL;
        return tlen + len;
  }
@@@ -832,9 -830,10 +832,9 @@@ static ssize_t __write_ports(struct fil
  static ssize_t write_ports(struct file *file, char *buf, size_t size)
  {
        ssize_t rv;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
  
        mutex_lock(&nfsd_mutex);
 -      rv = __write_ports(file, buf, size, net);
 +      rv = __write_ports(file, buf, size, netns(file));
        mutex_unlock(&nfsd_mutex);
        return rv;
  }
@@@ -866,7 -865,8 +866,7 @@@ int nfsd_max_blksize
  static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
  {
        char *mesg = buf;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
  
        if (size > 0) {
                int bsize;
  static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
  {
        char *mesg = buf;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
        unsigned int maxconn = nn->max_connections;
  
        if (size > 0) {
@@@ -996,7 -997,8 +996,7 @@@ static ssize_t nfsd4_write_time(struct 
   */
  static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
  {
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
  }
  
   */
  static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
  {
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
  }
  
@@@ -1068,7 -1071,8 +1068,7 @@@ static ssize_t __write_recoverydir(stru
  static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
  {
        ssize_t rv;
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
  
        mutex_lock(&nfsd_mutex);
        rv = __write_recoverydir(file, buf, size, nn);
   */
  static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
  {
 -      struct net *net = file->f_dentry->d_sb->s_fs_info;
 -      struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
  
        if (size > 0) {
                switch(buf[0]) {
diff --combined fs/nfsd/vfs.c
@@@ -16,6 -16,7 +16,7 @@@
  #include <linux/fs.h>
  #include <linux/file.h>
  #include <linux/splice.h>
+ #include <linux/falloc.h>
  #include <linux/fcntl.h>
  #include <linux/namei.h>
  #include <linux/delay.h>
@@@ -533,6 -534,26 +534,26 @@@ __be32 nfsd4_set_nfs4_label(struct svc_
  }
  #endif
  
+ __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                          struct file *file, loff_t offset, loff_t len,
+                          int flags)
+ {
+       __be32 err;
+       int error;
+       if (!S_ISREG(file_inode(file)->i_mode))
+               return nfserr_inval;
+       err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE);
+       if (err)
+               return err;
+       error = vfs_fallocate(file, flags, offset, len);
+       if (!error)
+               error = commit_metadata(fhp);
+       return nfserrno(error);
+ }
  #endif /* defined(CONFIG_NFSD_V4) */
  
  #ifdef CONFIG_NFSD_V3
@@@ -881,7 -902,7 +902,7 @@@ static __be3
  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)
+       if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
                return nfsd_splice_read(rqstp, file, offset, count);
        else
                return nfsd_readv(file, offset, vec, vlen, count);
@@@ -930,6 -951,7 +951,6 @@@ nfsd_vfs_write(struct svc_rqst *rqstp, 
                                unsigned long *cnt, int *stablep)
  {
        struct svc_export       *exp;
 -      struct dentry           *dentry;
        struct inode            *inode;
        mm_segment_t            oldfs;
        __be32                  err = 0;
        int                     stable = *stablep;
        int                     use_wgather;
        loff_t                  pos = offset;
+       loff_t                  end = LLONG_MAX;
        unsigned int            pflags = current->flags;
  
-       if (rqstp->rq_local)
+       if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
                /*
                 * We want less throttling in balance_dirty_pages()
                 * and shrink_inactive_list() so that nfs to
                 */
                current->flags |= PF_LESS_THROTTLE;
  
 -      dentry = file->f_path.dentry;
 -      inode = dentry->d_inode;
 +      inode = file_inode(file);
        exp   = fhp->fh_export;
  
        use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp);
        fsnotify_modify(file);
  
        if (stable) {
-               if (use_wgather)
+               if (use_wgather) {
                        host_err = wait_for_concurrent_writes(file);
-               else
-                       host_err = vfs_fsync_range(file, offset, offset+*cnt, 0);
+               } else {
+                       if (*cnt)
+                               end = offset + *cnt - 1;
+                       host_err = vfs_fsync_range(file, offset, end, 0);
+               }
        }
  
  out_nfserr:
                err = 0;
        else
                err = nfserrno(host_err);
-       if (rqstp->rq_local)
+       if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
                tsk_restore_flags(current, pflags, PF_LESS_THROTTLE);
        return err;
  }
@@@ -1817,12 -1844,10 +1842,12 @@@ struct readdir_data 
        int             full;
  };
  
 -static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
 -                               loff_t offset, u64 ino, unsigned int d_type)
 +static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name,
 +                               int namlen, loff_t offset, u64 ino,
 +                               unsigned int d_type)
  {
 -      struct readdir_data *buf = __buf;
 +      struct readdir_data *buf =
 +              container_of(ctx, struct readdir_data, ctx);
        struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
        unsigned int reclen;
  
        return 0;
  }
  
 -static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
 +static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
                                    struct readdir_cd *cdp, loff_t *offsetp)
  {
        struct buffered_dirent *de;
   */
  __be32
  nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, 
 -           struct readdir_cd *cdp, filldir_t func)
 +           struct readdir_cd *cdp, nfsd_filldir_t func)
  {
        __be32          err;
        struct file     *file;
diff --combined fs/nfsd/vfs.h
@@@ -36,7 -36,7 +36,7 @@@
  /*
   * Callback function for readdir
   */
 -typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
 +typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
  
  /* nfsd/vfs.c */
  int           nfsd_racache_init(int);
@@@ -54,6 -54,8 +54,8 @@@ int nfsd_mountpoint(struct dentry *, st
  #ifdef CONFIG_NFSD_V4
  __be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
                    struct xdr_netobj *);
+ __be32                nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
+                                   struct file *, loff_t, loff_t, int);
  #endif /* CONFIG_NFSD_V4 */
  __be32                nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
@@@ -95,7 -97,7 +97,7 @@@ __be32                nfsd_rename(struct svc_rqst *
  __be32                nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
                                char *name, int len);
  __be32                nfsd_readdir(struct svc_rqst *, struct svc_fh *,
 -                           loff_t *, struct readdir_cd *, filldir_t);
 +                           loff_t *, struct readdir_cd *, nfsd_filldir_t);
  __be32                nfsd_statfs(struct svc_rqst *, struct svc_fh *,
                                struct kstatfs *, int access);
  
diff --combined fs/open.c
+++ b/fs/open.c
@@@ -222,7 -222,7 +222,7 @@@ SYSCALL_DEFINE2(ftruncate64, unsigned i
  #endif /* BITS_PER_LONG == 32 */
  
  
- int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
  {
        struct inode *inode = file_inode(file);
        long ret;
  
        sb_start_write(inode->i_sb);
        ret = file->f_op->fallocate(file, mode, offset, len);
 +
 +      /*
 +       * Create inotify and fanotify events.
 +       *
 +       * To keep the logic simple always create events if fallocate succeeds.
 +       * This implies that events are even created if the file size remains
 +       * unchanged, e.g. when using flag FALLOC_FL_KEEP_SIZE.
 +       */
 +      if (ret == 0)
 +              fsnotify_modify(file);
 +
        sb_end_write(inode->i_sb);
        return ret;
  }
+ EXPORT_SYMBOL_GPL(vfs_fallocate);
  
  SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
  {
        int error = -EBADF;
  
        if (f.file) {
-               error = do_fallocate(f.file, mode, offset, len);
+               error = vfs_fallocate(f.file, mode, offset, len);
                fdput(f);
        }
        return error;
@@@ -527,7 -517,7 +528,7 @@@ SYSCALL_DEFINE2(fchmod, unsigned int, f
        int err = -EBADF;
  
        if (f.file) {
 -              audit_inode(NULL, f.file->f_path.dentry, 0);
 +              audit_file(f.file);
                err = chmod_common(&f.file->f_path, mode);
                fdput(f);
        }
@@@ -653,7 -643,7 +654,7 @@@ SYSCALL_DEFINE3(fchown, unsigned int, f
        error = mnt_want_write_file(f.file);
        if (error)
                goto out_fput;
 -      audit_inode(NULL, f.file->f_path.dentry, 0);
 +      audit_file(f.file);
        error = chown_common(&f.file->f_path, user, group);
        mnt_drop_write_file(f.file);
  out_fput:
diff --combined include/linux/fs.h
@@@ -18,7 -18,6 +18,7 @@@
  #include <linux/pid.h>
  #include <linux/bug.h>
  #include <linux/mutex.h>
 +#include <linux/rwsem.h>
  #include <linux/capability.h>
  #include <linux/semaphore.h>
  #include <linux/fiemap.h>
@@@ -402,7 -401,7 +402,7 @@@ struct address_space 
        atomic_t                i_mmap_writable;/* count VM_SHARED mappings */
        struct rb_root          i_mmap;         /* tree of private and shared mappings */
        struct list_head        i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
 -      struct mutex            i_mmap_mutex;   /* protect tree, count, list */
 +      struct rw_semaphore     i_mmap_rwsem;   /* protect tree, count, list */
        /* Protected by tree_lock together with the radix tree */
        unsigned long           nrpages;        /* number of total pages */
        unsigned long           nrshadows;      /* number of shadow entries */
@@@ -468,26 -467,6 +468,26 @@@ struct block_device 
  
  int mapping_tagged(struct address_space *mapping, int tag);
  
 +static inline void i_mmap_lock_write(struct address_space *mapping)
 +{
 +      down_write(&mapping->i_mmap_rwsem);
 +}
 +
 +static inline void i_mmap_unlock_write(struct address_space *mapping)
 +{
 +      up_write(&mapping->i_mmap_rwsem);
 +}
 +
 +static inline void i_mmap_lock_read(struct address_space *mapping)
 +{
 +      down_read(&mapping->i_mmap_rwsem);
 +}
 +
 +static inline void i_mmap_unlock_read(struct address_space *mapping)
 +{
 +      up_read(&mapping->i_mmap_rwsem);
 +}
 +
  /*
   * Might pages of this file be mapped into userspace?
   */
@@@ -627,6 -606,9 +627,6 @@@ struct inode 
        const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
        struct file_lock        *i_flock;
        struct address_space    i_data;
 -#ifdef CONFIG_QUOTA
 -      struct dquot            *i_dquot[MAXQUOTAS];
 -#endif
        struct list_head        i_devices;
        union {
                struct pipe_inode_info  *i_pipe;
@@@ -807,6 -789,7 +807,6 @@@ struct file 
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
 -#define f_dentry      f_path.dentry
        struct inode            *f_inode;       /* cached value */
        const struct file_operations    *f_op;
  
@@@ -1241,7 -1224,6 +1241,7 @@@ struct super_block 
        struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
        struct hlist_node       s_instances;
 +      unsigned int            s_quota_types;  /* Bitmask of supported quota types */
        struct quota_info       s_dquot;        /* Diskquota specific options */
  
        struct sb_writers       s_writers;
@@@ -1485,10 -1467,7 +1485,10 @@@ int fiemap_check_flags(struct fiemap_ex
   * This allows the kernel to read directories into kernel space or
   * to have different dirent layouts depending on the binary type.
   */
 -typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
 +struct dir_context;
 +typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
 +                       unsigned);
 +
  struct dir_context {
        const filldir_t actor;
        loff_t pos;
@@@ -1518,7 -1497,6 +1518,7 @@@ struct file_operations 
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
 +      void (*mremap)(struct file *, struct vm_area_struct *);
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
        int (*setlease)(struct file *, long, struct file_lock **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
 -      int (*show_fdinfo)(struct seq_file *m, struct file *f);
 +      void (*show_fdinfo)(struct seq_file *m, struct file *f);
  };
  
  struct inode_operations {
@@@ -1582,7 -1560,6 +1582,7 @@@ ssize_t rw_copy_check_uvector(int type
                              struct iovec *fast_pointer,
                              struct iovec **ret_pointer);
  
 +extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
  extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
  extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
  extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
@@@ -1600,9 -1577,7 +1600,9 @@@ struct super_operations 
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
 +      int (*freeze_super) (struct super_block *);
        int (*freeze_fs) (struct super_block *);
 +      int (*thaw_super) (struct super_block *);
        int (*unfreeze_fs) (struct super_block *);
        int (*statfs) (struct dentry *, struct kstatfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
  #ifdef CONFIG_QUOTA
        ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
        ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 +      struct dquot **(*get_dquots)(struct inode *);
  #endif
        int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
        long (*nr_cached_objects)(struct super_block *, int);
@@@ -2086,7 -2060,7 +2086,7 @@@ struct filename 
  extern long vfs_truncate(struct path *, loff_t);
  extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
- extern int do_fallocate(struct file *file, int mode, loff_t offset,
+ extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
                        loff_t len);
  extern long do_sys_open(int dfd, const char __user *filename, int flags,
                        umode_t mode);
@@@ -2098,7 -2072,6 +2098,7 @@@ extern int vfs_open(const struct path *
  extern struct file * dentry_open(const struct path *, int, const struct cred *);
  extern int filp_close(struct file *, fl_owner_t id);
  
 +extern struct filename *getname_flags(const char __user *, int, int *);
  extern struct filename *getname(const char __user *);
  extern struct filename *getname_kernel(const char *);
  
@@@ -2813,11 -2786,6 +2813,11 @@@ static inline void inode_has_no_xattr(s
                inode->i_flags |= S_NOSEC;
  }
  
 +static inline bool is_root_inode(struct inode *inode)
 +{
 +      return inode == inode->i_sb->s_root->d_inode;
 +}
 +
  static inline bool dir_emit(struct dir_context *ctx,
                            const char *name, int namelen,
                            u64 ino, unsigned type)