]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
nfs: disintegrate UAPI for nfs
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 9 Oct 2012 22:35:22 +0000 (18:35 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Tue, 9 Oct 2012 22:35:22 +0000 (18:35 -0400)
This is to complete part of the Userspace API (UAPI) disintegration for which
the preparatory patches were pulled recently.  After these patches, userspace
headers will be segregated into:

        include/uapi/linux/.../foo.h

for the userspace interface stuff, and:

        include/linux/.../foo.h

for the strictly kernel internal stuff.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1  2 
fs/locks.c
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c

diff --combined fs/locks.c
index 669911e4af9ddec89a6b8141e87bdd97618d12cb,abc7dc6c490b6dc7ca6e9119c585dc10b1a2d3d9..a94e331a52a2febbf46a4df702156c1a013b2990
@@@ -1289,7 -1289,7 +1289,7 @@@ EXPORT_SYMBOL(__break_lease)
  void lease_get_mtime(struct inode *inode, struct timespec *time)
  {
        struct file_lock *flock = inode->i_flock;
 -      if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK))
 +      if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
                *time = current_fs_time(inode->i_sb);
        else
                *time = inode->i_mtime;
@@@ -1625,15 -1625,13 +1625,13 @@@ EXPORT_SYMBOL(flock_lock_file_wait)
   */
  SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
  {
-       struct file *filp;
-       int fput_needed;
+       struct fd f = fdget(fd);
        struct file_lock *lock;
        int can_sleep, unlock;
        int error;
  
        error = -EBADF;
-       filp = fget_light(fd, &fput_needed);
-       if (!filp)
+       if (!f.file)
                goto out;
  
        can_sleep = !(cmd & LOCK_NB);
        unlock = (cmd == LOCK_UN);
  
        if (!unlock && !(cmd & LOCK_MAND) &&
-           !(filp->f_mode & (FMODE_READ|FMODE_WRITE)))
+           !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
                goto out_putf;
  
-       error = flock_make_lock(filp, &lock, cmd);
+       error = flock_make_lock(f.file, &lock, cmd);
        if (error)
                goto out_putf;
        if (can_sleep)
                lock->fl_flags |= FL_SLEEP;
  
-       error = security_file_lock(filp, lock->fl_type);
+       error = security_file_lock(f.file, lock->fl_type);
        if (error)
                goto out_free;
  
-       if (filp->f_op && filp->f_op->flock)
-               error = filp->f_op->flock(filp,
+       if (f.file->f_op && f.file->f_op->flock)
+               error = f.file->f_op->flock(f.file,
                                          (can_sleep) ? F_SETLKW : F_SETLK,
                                          lock);
        else
-               error = flock_lock_file_wait(filp, lock);
+               error = flock_lock_file_wait(f.file, lock);
  
   out_free:
        locks_free_lock(lock);
  
   out_putf:
-       fput_light(filp, fput_needed);
+       fdput(f);
   out:
        return error;
  }
@@@ -2187,8 -2185,8 +2185,8 @@@ static void lock_get_status(struct seq_
        } else {
                seq_printf(f, "%s ",
                               (lease_breaking(fl))
 -                             ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
 -                             : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
 +                             ? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ "
 +                             : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ ");
        }
        if (inode) {
  #ifdef WE_CAN_BREAK_LSLK_NOW
diff --combined fs/nfsd/nfs4state.c
index 412b888faecbac52265b79c52ee91a352a3f1a5f,48a1bad373342b10b689927faf002cf444043b22..d0237f872cc4e1fe49060120d725f729783dc245
@@@ -758,7 -758,7 +758,7 @@@ static void nfsd4_put_drc_mem(int slots
        spin_unlock(&nfsd_drc_lock);
  }
  
 -static struct nfsd4_session *alloc_session(int slotsize, int numslots)
 +static struct nfsd4_session *__alloc_session(int slotsize, int numslots)
  {
        struct nfsd4_session *new;
        int mem, i;
@@@ -852,28 -852,35 +852,28 @@@ static int nfsd4_register_conn(struct n
        return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
  }
  
 -static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
 +static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
  {
 -      struct nfsd4_conn *conn;
        int ret;
  
 -      conn = alloc_conn(rqstp, dir);
 -      if (!conn)
 -              return nfserr_jukebox;
        nfsd4_hash_conn(conn, ses);
        ret = nfsd4_register_conn(conn);
        if (ret)
                /* oops; xprt is already down: */
                nfsd4_conn_lost(&conn->cn_xpt_user);
 -      if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN &&
 -              dir & NFS4_CDFC4_BACK) {
 +      if (conn->cn_flags & NFS4_CDFC4_BACK) {
                /* callback channel may be back up */
                nfsd4_probe_callback(ses->se_client);
        }
 -      return nfs_ok;
  }
  
 -static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
 +static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
  {
        u32 dir = NFS4_CDFC4_FORE;
  
 -      if (ses->se_flags & SESSION4_BACK_CHAN)
 +      if (cses->flags & SESSION4_BACK_CHAN)
                dir |= NFS4_CDFC4_BACK;
 -
 -      return nfsd4_new_conn(rqstp, ses, dir);
 +      return alloc_conn(rqstp, dir);
  }
  
  /* must be called under client_lock */
@@@ -896,21 -903,20 +896,21 @@@ static void nfsd4_del_conns(struct nfsd
        spin_unlock(&clp->cl_lock);
  }
  
 +static void __free_session(struct nfsd4_session *ses)
 +{
 +      nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs);
 +      free_session_slots(ses);
 +      kfree(ses);
 +}
 +
  static void free_session(struct kref *kref)
  {
        struct nfsd4_session *ses;
 -      int mem;
  
        lockdep_assert_held(&client_lock);
        ses = container_of(kref, struct nfsd4_session, se_ref);
        nfsd4_del_conns(ses);
 -      spin_lock(&nfsd_drc_lock);
 -      mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
 -      nfsd_drc_mem_used -= mem;
 -      spin_unlock(&nfsd_drc_lock);
 -      free_session_slots(ses);
 -      kfree(ses);
 +      __free_session(ses);
  }
  
  void nfsd4_put_session(struct nfsd4_session *ses)
        spin_unlock(&client_lock);
  }
  
 -static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
 +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
  {
        struct nfsd4_session *new;
 -      struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
        int numslots, slotsize;
 -      __be32 status;
 -      int idx;
 -
        /*
         * Note decreasing slot size below client's request may
         * make it difficult for client to function correctly, whereas
        if (numslots < 1)
                return NULL;
  
 -      new = alloc_session(slotsize, numslots);
 +      new = __alloc_session(slotsize, numslots);
        if (!new) {
                nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
                return NULL;
        }
        init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
 +      return new;
 +}
 +
 +static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
 +{
 +      int idx;
  
        new->se_client = clp;
        gen_sessionid(new);
        spin_unlock(&clp->cl_lock);
        spin_unlock(&client_lock);
  
 -      status = nfsd4_new_conn_from_crses(rqstp, new);
 -      /* whoops: benny points out, status is ignored! (err, or bogus) */
 -      if (status) {
 -              spin_lock(&client_lock);
 -              free_session(&new->se_ref);
 -              spin_unlock(&client_lock);
 -              return NULL;
 -      }
        if (cses->flags & SESSION4_BACK_CHAN) {
                struct sockaddr *sa = svc_addr(rqstp);
                /*
                rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
                clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
        }
 -      nfsd4_probe_callback(clp);
        return new;
  }
  
@@@ -1118,7 -1131,7 +1118,7 @@@ unhash_client_locked(struct nfs4_clien
  }
  
  static void
 -expire_client(struct nfs4_client *clp)
 +destroy_client(struct nfs4_client *clp)
  {
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
        spin_unlock(&client_lock);
  }
  
 +static void expire_client(struct nfs4_client *clp)
 +{
 +      nfsd4_client_record_remove(clp);
 +      destroy_client(clp);
 +}
 +
  static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
  {
        memcpy(target->cl_verifier.data, source->data,
@@@ -1216,26 -1223,10 +1216,26 @@@ static bool groups_equal(struct group_i
        return true;
  }
  
 +/*
 + * RFC 3530 language requires clid_inuse be returned when the
 + * "principal" associated with a requests differs from that previously
 + * used.  We use uid, gid's, and gss principal string as our best
 + * approximation.  We also don't want to allow non-gss use of a client
 + * established using gss: in theory cr_principal should catch that
 + * change, but in practice cr_principal can be null even in the gss case
 + * since gssd doesn't always pass down a principal string.
 + */
 +static bool is_gss_cred(struct svc_cred *cr)
 +{
 +      /* Is cr_flavor one of the gss "pseudoflavors"?: */
 +      return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
 +}
 +
 +
  static bool
  same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
  {
 -      if ((cr1->cr_flavor != cr2->cr_flavor)
 +      if ((is_gss_cred(cr1) != is_gss_cred(cr2))
                || (cr1->cr_uid != cr2->cr_uid)
                || (cr1->cr_gid != cr2->cr_gid)
                || !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
@@@ -1349,15 -1340,13 +1349,15 @@@ move_to_confirmed(struct nfs4_client *c
  }
  
  static struct nfs4_client *
 -find_confirmed_client(clientid_t *clid)
 +find_confirmed_client(clientid_t *clid, bool sessions)
  {
        struct nfs4_client *clp;
        unsigned int idhashval = clientid_hashval(clid->cl_id);
  
        list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
                if (same_clid(&clp->cl_clientid, clid)) {
 +                      if ((bool)clp->cl_minorversion != sessions)
 +                              return NULL;
                        renew_client(clp);
                        return clp;
                }
  }
  
  static struct nfs4_client *
 -find_unconfirmed_client(clientid_t *clid)
 +find_unconfirmed_client(clientid_t *clid, bool sessions)
  {
        struct nfs4_client *clp;
        unsigned int idhashval = clientid_hashval(clid->cl_id);
  
        list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
 -              if (same_clid(&clp->cl_clientid, clid))
 +              if (same_clid(&clp->cl_clientid, clid)) {
 +                      if ((bool)clp->cl_minorversion != sessions)
 +                              return NULL;
                        return clp;
 +              }
        }
        return NULL;
  }
@@@ -1665,7 -1651,6 +1665,7 @@@ out_new
                status = nfserr_jukebox;
                goto out;
        }
 +      new->cl_minorversion = 1;
  
        gen_clid(new);
        add_to_unconfirmed(new, strhashval);
@@@ -1758,71 -1743,67 +1758,71 @@@ nfsd4_create_session(struct svc_rqst *r
        struct sockaddr *sa = svc_addr(rqstp);
        struct nfs4_client *conf, *unconf;
        struct nfsd4_session *new;
 +      struct nfsd4_conn *conn;
        struct nfsd4_clid_slot *cs_slot = NULL;
 -      bool confirm_me = false;
        __be32 status = 0;
  
        if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
                return nfserr_inval;
 +      if (check_forechannel_attrs(cr_ses->fore_channel))
 +              return nfserr_toosmall;
 +      new = alloc_session(&cr_ses->fore_channel);
 +      if (!new)
 +              return nfserr_jukebox;
 +      status = nfserr_jukebox;
 +      conn = alloc_conn_from_crses(rqstp, cr_ses);
 +      if (!conn)
 +              goto out_free_session;
  
        nfs4_lock_state();
 -      unconf = find_unconfirmed_client(&cr_ses->clientid);
 -      conf = find_confirmed_client(&cr_ses->clientid);
 +      unconf = find_unconfirmed_client(&cr_ses->clientid, true);
 +      conf = find_confirmed_client(&cr_ses->clientid, true);
  
        if (conf) {
                cs_slot = &conf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status == nfserr_replay_cache) {
                        status = nfsd4_replay_create_session(cr_ses, cs_slot);
 -                      goto out;
 +                      goto out_free_conn;
                } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
                        status = nfserr_seq_misordered;
 -                      goto out;
 +                      goto out_free_conn;
                }
        } else if (unconf) {
 +              unsigned int hash;
 +              struct nfs4_client *old;
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
                    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
                        status = nfserr_clid_inuse;
 -                      goto out;
 +                      goto out_free_conn;
                }
                cs_slot = &unconf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status) {
                        /* an unconfirmed replay returns misordered */
                        status = nfserr_seq_misordered;
 -                      goto out;
 +                      goto out_free_conn;
                }
 -              confirm_me = true;
 +              hash = clientstr_hashval(unconf->cl_recdir);
 +              old = find_confirmed_client_by_str(unconf->cl_recdir, hash);
 +              if (old)
 +                      expire_client(old);
 +              move_to_confirmed(unconf);
                conf = unconf;
        } else {
                status = nfserr_stale_clientid;
 -              goto out;
 +              goto out_free_conn;
        }
 -
 -      /*
 -       * XXX: we should probably set this at creation time, and check
 -       * for consistent minorversion use throughout:
 -       */
 -      conf->cl_minorversion = 1;
 +      status = nfs_ok;
        /*
         * We do not support RDMA or persistent sessions
         */
        cr_ses->flags &= ~SESSION4_PERSIST;
        cr_ses->flags &= ~SESSION4_RDMA;
  
 -      status = nfserr_toosmall;
 -      if (check_forechannel_attrs(cr_ses->fore_channel))
 -              goto out;
 +      init_session(rqstp, new, conf, cr_ses);
 +      nfsd4_init_conn(rqstp, conn, new);
  
 -      status = nfserr_jukebox;
 -      new = alloc_init_session(rqstp, conf, cr_ses);
 -      if (!new)
 -              goto out;
 -      status = nfs_ok;
        memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
               NFS4_MAX_SESSIONID_LEN);
        memcpy(&cr_ses->fore_channel, &new->se_fchannel,
  
        /* cache solo and embedded create sessions under the state lock */
        nfsd4_cache_create_session(cr_ses, cs_slot, status);
 -      if (confirm_me) {
 -              unsigned int hash = clientstr_hashval(unconf->cl_recdir);
 -              struct nfs4_client *old =
 -                      find_confirmed_client_by_str(conf->cl_recdir, hash);
 -              if (old)
 -                      expire_client(old);
 -              move_to_confirmed(conf);
 -      }
  out:
        nfs4_unlock_state();
        dprintk("%s returns %d\n", __func__, ntohl(status));
        return status;
 +out_free_conn:
 +      free_conn(conn);
 +out_free_session:
 +      __free_session(new);
 +      goto out;
  }
  
  static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
@@@ -1870,7 -1854,6 +1870,7 @@@ __be32 nfsd4_bind_conn_to_session(struc
                     struct nfsd4_bind_conn_to_session *bcts)
  {
        __be32 status;
 +      struct nfsd4_conn *conn;
  
        if (!nfsd4_last_compound_op(rqstp))
                return nfserr_not_only_op;
                return nfserr_badsession;
  
        status = nfsd4_map_bcts_dir(&bcts->dir);
 -      if (!status)
 -              nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
 -      return status;
 +      if (status)
 +              return status;
 +      conn = alloc_conn(rqstp, bcts->dir);
 +      if (!conn)
 +              return nfserr_jukebox;
 +      nfsd4_init_conn(rqstp, conn, cstate->session);
 +      return nfs_ok;
  }
  
  static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
@@@ -2106,8 -2085,8 +2106,8 @@@ nfsd4_destroy_clientid(struct svc_rqst 
        __be32 status = 0;
  
        nfs4_lock_state();
 -      unconf = find_unconfirmed_client(&dc->clientid);
 -      conf = find_confirmed_client(&dc->clientid);
 +      unconf = find_unconfirmed_client(&dc->clientid, true);
 +      conf = find_confirmed_client(&dc->clientid, true);
  
        if (conf) {
                clp = conf;
@@@ -2221,6 -2200,10 +2221,6 @@@ nfsd4_setclientid(struct svc_rqst *rqst
                copy_clid(new, conf);
        else /* case 4 (new client) or cases 2, 3 (client reboot): */
                gen_clid(new);
 -      /*
 -       * XXX: we should probably set this at creation time, and check
 -       * for consistent minorversion use throughout:
 -       */
        new->cl_minorversion = 0;
        gen_callback(new, setclid, rqstp);
        add_to_unconfirmed(new, strhashval);
@@@ -2249,8 -2232,8 +2249,8 @@@ nfsd4_setclientid_confirm(struct svc_rq
                return nfserr_stale_clientid;
        nfs4_lock_state();
  
 -      conf = find_confirmed_client(clid);
 -      unconf = find_unconfirmed_client(clid);
 +      conf = find_confirmed_client(clid, false);
 +      unconf = find_unconfirmed_client(clid, false);
        /*
         * We try hard to give out unique clientid's, so if we get an
         * attempt to confirm the same clientid with a different cred,
                unsigned int hash = clientstr_hashval(unconf->cl_recdir);
  
                conf = find_confirmed_client_by_str(unconf->cl_recdir, hash);
 -              if (conf) {
 -                      nfsd4_client_record_remove(conf);
 +              if (conf)
                        expire_client(conf);
 -              }
                move_to_confirmed(unconf);
                nfsd4_probe_callback(unconf);
        }
@@@ -2462,20 -2447,16 +2462,20 @@@ same_owner_str(struct nfs4_stateowner *
  }
  
  static struct nfs4_openowner *
 -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
 +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions)
  {
        struct nfs4_stateowner *so;
        struct nfs4_openowner *oo;
 +      struct nfs4_client *clp;
  
        list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
                if (!so->so_is_open_owner)
                        continue;
                if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
                        oo = openowner(so);
 +                      clp = oo->oo_owner.so_client;
 +                      if ((bool)clp->cl_minorversion != sessions)
 +                              return NULL;
                        renew_client(oo->oo_owner.so_client);
                        return oo;
                }
@@@ -2619,10 -2600,10 +2619,10 @@@ nfsd4_process_open1(struct nfsd4_compou
                return nfserr_jukebox;
  
        strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
 -      oo = find_openstateowner_str(strhashval, open);
 +      oo = find_openstateowner_str(strhashval, open, cstate->minorversion);
        open->op_openowner = oo;
        if (!oo) {
 -              clp = find_confirmed_client(clientid);
 +              clp = find_confirmed_client(clientid, cstate->minorversion);
                if (clp == NULL)
                        return nfserr_expired;
                goto new_owner;
@@@ -2724,6 -2705,11 +2724,6 @@@ nfs4_check_open(struct nfs4_file *fp, s
        return nfs_ok;
  }
  
 -static void nfs4_free_stateid(struct nfs4_ol_stateid *s)
 -{
 -      kmem_cache_free(stateid_slab, s);
 -}
 -
  static inline int nfs4_access_to_access(u32 nfs4_access)
  {
        int flags = 0;
@@@ -2851,8 -2837,7 +2851,7 @@@ static int nfs4_setlease(struct nfs4_de
                return -ENOMEM;
        }
        fp->fi_lease = fl;
-       fp->fi_deleg_file = fl->fl_file;
-       get_file(fp->fi_deleg_file);
+       fp->fi_deleg_file = get_file(fl->fl_file);
        atomic_set(&fp->fi_delegees, 1);
        list_add(&dp->dl_perfile, &fp->fi_delegations);
        return 0;
@@@ -3102,7 -3087,7 +3101,7 @@@ void nfsd4_cleanup_open_state(struct nf
        if (open->op_file)
                nfsd4_free_file(open->op_file);
        if (open->op_stp)
 -              nfs4_free_stateid(open->op_stp);
 +              free_generic_stateid(open->op_stp);
  }
  
  __be32
@@@ -3119,7 -3104,7 +3118,7 @@@ nfsd4_renew(struct svc_rqst *rqstp, str
        status = nfserr_stale_clientid;
        if (STALE_CLIENTID(clid, nn))
                goto out;
 -      clp = find_confirmed_client(clid);
 +      clp = find_confirmed_client(clid, cstate->minorversion);
        status = nfserr_expired;
        if (clp == NULL) {
                /* We assume the client took too long to RENEW. */
@@@ -3195,6 -3180,7 +3194,6 @@@ nfs4_laundromat(void
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                dprintk("NFSD: purging unused client (clientid %08x)\n",
                        clp->cl_clientid.cl_id);
 -              nfsd4_client_record_remove(clp);
                expire_client(clp);
        }
        spin_lock(&recall_lock);
@@@ -3386,7 -3372,7 +3385,7 @@@ static __be32 nfsd4_validate_stateid(st
        return nfs_ok;
  }
  
 -static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
 +static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions)
  {
        struct nfs4_client *cl;
        struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
                return nfserr_bad_stateid;
        if (STALE_STATEID(stateid, nn))
                return nfserr_stale_stateid;
 -      cl = find_confirmed_client(&stateid->si_opaque.so_clid);
 +      cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions);
        if (!cl)
                return nfserr_expired;
        *s = find_stateid_by_type(cl, stateid, typemask);
@@@ -3428,7 -3414,7 +3427,7 @@@ nfs4_preprocess_stateid_op(struct net *
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
                return check_special_stateids(net, current_fh, stateid, flags);
  
 -      status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
 +      status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion);
        if (status)
                return status;
        status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
@@@ -3578,7 -3564,7 +3577,7 @@@ nfs4_preprocess_seqid_op(struct nfsd4_c
                seqid, STATEID_VAL(stateid));
  
        *stpp = NULL;
 -      status = nfsd4_lookup_stateid(stateid, typemask, &s);
 +      status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion);
        if (status)
                return status;
        *stpp = openlockstateid(s);
@@@ -3779,7 -3765,6 +3778,7 @@@ nfsd4_close(struct svc_rqst *rqstp, str
        memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
  
        nfsd4_close_open_stateid(stp);
 +      release_last_closed_stateid(oo);
        oo->oo_last_closed_stid = stp;
  
        if (list_empty(&oo->oo_owner.so_stateids)) {
@@@ -3816,7 -3801,7 +3815,7 @@@ nfsd4_delegreturn(struct svc_rqst *rqst
        inode = cstate->current_fh.fh_dentry->d_inode;
  
        nfs4_lock_state();
 -      status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
 +      status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion);
        if (status)
                goto out;
        dp = delegstateid(s);
@@@ -4060,8 -4045,8 +4059,8 @@@ nfsd4_lock(struct svc_rqst *rqstp, stru
        struct nfs4_lockowner *lock_sop = NULL;
        struct nfs4_ol_stateid *lock_stp;
        struct file *filp = NULL;
 -      struct file_lock file_lock;
 -      struct file_lock conflock;
 +      struct file_lock *file_lock = NULL;
 +      struct file_lock *conflock = NULL;
        __be32 status = 0;
        bool new_state = false;
        int lkflg;
        if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim)
                goto out;
  
 -      locks_init_lock(&file_lock);
 +      file_lock = locks_alloc_lock();
 +      if (!file_lock) {
 +              dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
 +              status = nfserr_jukebox;
 +              goto out;
 +      }
 +
 +      locks_init_lock(file_lock);
        switch (lock->lk_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
                        filp = find_readable_file(lock_stp->st_file);
                        if (filp)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
 -                      file_lock.fl_type = F_RDLCK;
 +                      file_lock->fl_type = F_RDLCK;
                        break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
                        filp = find_writeable_file(lock_stp->st_file);
                        if (filp)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
 -                      file_lock.fl_type = F_WRLCK;
 +                      file_lock->fl_type = F_WRLCK;
                        break;
                default:
                        status = nfserr_inval;
                status = nfserr_openmode;
                goto out;
        }
 -      file_lock.fl_owner = (fl_owner_t)lock_sop;
 -      file_lock.fl_pid = current->tgid;
 -      file_lock.fl_file = filp;
 -      file_lock.fl_flags = FL_POSIX;
 -      file_lock.fl_lmops = &nfsd_posix_mng_ops;
 -
 -      file_lock.fl_start = lock->lk_offset;
 -      file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
 -      nfs4_transform_lock_offset(&file_lock);
 -
 -      /*
 -      * Try to lock the file in the VFS.
 -      * Note: locks.c uses the BKL to protect the inode's lock list.
 -      */
 +      file_lock->fl_owner = (fl_owner_t)lock_sop;
 +      file_lock->fl_pid = current->tgid;
 +      file_lock->fl_file = filp;
 +      file_lock->fl_flags = FL_POSIX;
 +      file_lock->fl_lmops = &nfsd_posix_mng_ops;
 +      file_lock->fl_start = lock->lk_offset;
 +      file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
 +      nfs4_transform_lock_offset(file_lock);
 +
 +      conflock = locks_alloc_lock();
 +      if (!conflock) {
 +              dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
 +              status = nfserr_jukebox;
 +              goto out;
 +      }
  
 -      err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
 +      err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
        switch (-err) {
        case 0: /* success! */
                update_stateid(&lock_stp->st_stid.sc_stateid);
        case (EAGAIN):          /* conflock holds conflicting lock */
                status = nfserr_denied;
                dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
 -              nfs4_set_lock_denied(&conflock, &lock->lk_denied);
 +              nfs4_set_lock_denied(conflock, &lock->lk_denied);
                break;
        case (EDEADLK):
                status = nfserr_deadlock;
                release_lockowner(lock_sop);
        if (!cstate->replay_owner)
                nfs4_unlock_state();
 +      if (file_lock)
 +              locks_free_lock(file_lock);
 +      if (conflock)
 +              locks_free_lock(conflock);
        return status;
  }
  
@@@ -4236,7 -4209,7 +4235,7 @@@ nfsd4_lockt(struct svc_rqst *rqstp, str
            struct nfsd4_lockt *lockt)
  {
        struct inode *inode;
 -      struct file_lock file_lock;
 +      struct file_lock *file_lock = NULL;
        struct nfs4_lockowner *lo;
        __be32 status;
        struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
                goto out;
  
        inode = cstate->current_fh.fh_dentry->d_inode;
 -      locks_init_lock(&file_lock);
 +      file_lock = locks_alloc_lock();
 +      if (!file_lock) {
 +              dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
 +              status = nfserr_jukebox;
 +              goto out;
 +      }
 +      locks_init_lock(file_lock);
        switch (lockt->lt_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
 -                      file_lock.fl_type = F_RDLCK;
 +                      file_lock->fl_type = F_RDLCK;
                break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
 -                      file_lock.fl_type = F_WRLCK;
 +                      file_lock->fl_type = F_WRLCK;
                break;
                default:
                        dprintk("NFSD: nfs4_lockt: bad lock type!\n");
  
        lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
        if (lo)
 -              file_lock.fl_owner = (fl_owner_t)lo;
 -      file_lock.fl_pid = current->tgid;
 -      file_lock.fl_flags = FL_POSIX;
 +              file_lock->fl_owner = (fl_owner_t)lo;
 +      file_lock->fl_pid = current->tgid;
 +      file_lock->fl_flags = FL_POSIX;
  
 -      file_lock.fl_start = lockt->lt_offset;
 -      file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
 +      file_lock->fl_start = lockt->lt_offset;
 +      file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
  
 -      nfs4_transform_lock_offset(&file_lock);
 +      nfs4_transform_lock_offset(file_lock);
  
 -      status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
 +      status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
        if (status)
                goto out;
  
 -      if (file_lock.fl_type != F_UNLCK) {
 +      if (file_lock->fl_type != F_UNLCK) {
                status = nfserr_denied;
 -              nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
 +              nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
        }
  out:
        nfs4_unlock_state();
 +      if (file_lock)
 +              locks_free_lock(file_lock);
        return status;
  }
  
@@@ -4311,7 -4276,7 +4310,7 @@@ nfsd4_locku(struct svc_rqst *rqstp, str
  {
        struct nfs4_ol_stateid *stp;
        struct file *filp = NULL;
 -      struct file_lock file_lock;
 +      struct file_lock *file_lock = NULL;
        __be32 status;
        int err;
                                                        
                status = nfserr_lock_range;
                goto out;
        }
 -      BUG_ON(!filp);
 -      locks_init_lock(&file_lock);
 -      file_lock.fl_type = F_UNLCK;
 -      file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
 -      file_lock.fl_pid = current->tgid;
 -      file_lock.fl_file = filp;
 -      file_lock.fl_flags = FL_POSIX; 
 -      file_lock.fl_lmops = &nfsd_posix_mng_ops;
 -      file_lock.fl_start = locku->lu_offset;
 -
 -      file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
 -      nfs4_transform_lock_offset(&file_lock);
 +      file_lock = locks_alloc_lock();
 +      if (!file_lock) {
 +              dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
 +              status = nfserr_jukebox;
 +              goto out;
 +      }
 +      locks_init_lock(file_lock);
 +      file_lock->fl_type = F_UNLCK;
 +      file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
 +      file_lock->fl_pid = current->tgid;
 +      file_lock->fl_file = filp;
 +      file_lock->fl_flags = FL_POSIX;
 +      file_lock->fl_lmops = &nfsd_posix_mng_ops;
 +      file_lock->fl_start = locku->lu_offset;
 +
 +      file_lock->fl_end = last_byte_offset(locku->lu_offset,
 +                                              locku->lu_length);
 +      nfs4_transform_lock_offset(file_lock);
  
        /*
        *  Try to unlock the file in the VFS.
        */
 -      err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
 +      err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
        if (err) {
                dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
                goto out_nfserr;
  out:
        if (!cstate->replay_owner)
                nfs4_unlock_state();
 +      if (file_lock)
 +              locks_free_lock(file_lock);
        return status;
  
  out_nfserr:
@@@ -4544,12 -4501,12 +4543,12 @@@ nfsd4_find_reclaim_client(struct nfs4_c
  * Called from OPEN. Look for clientid in reclaim list.
  */
  __be32
 -nfs4_check_open_reclaim(clientid_t *clid)
 +nfs4_check_open_reclaim(clientid_t *clid, bool sessions)
  {
        struct nfs4_client *clp;
  
        /* find clientid in conf_id_hashtbl */
 -      clp = find_confirmed_client(clid);
 +      clp = find_confirmed_client(clid, sessions);
        if (clp == NULL)
                return nfserr_reclaim_bad;
  
@@@ -4565,6 -4522,7 +4564,6 @@@ void nfsd_forget_clients(u64 num
  
        nfs4_lock_state();
        list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
 -              nfsd4_client_record_remove(clp);
                expire_client(clp);
                if (++count == num)
                        break;
@@@ -4624,7 -4582,7 +4623,7 @@@ void nfsd_forget_openowners(u64 num
        printk(KERN_INFO "NFSD: Forgot %d open owners", count);
  }
  
 -int nfsd_process_n_delegations(u64 num, struct list_head *list)
 +static int nfsd_process_n_delegations(u64 num, struct list_head *list)
  {
        int i, count = 0;
        struct nfs4_file *fp, *fnext;
@@@ -4789,11 -4747,11 +4788,11 @@@ __nfs4_state_shutdown(void
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                while (!list_empty(&conf_id_hashtbl[i])) {
                        clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
 -                      expire_client(clp);
 +                      destroy_client(clp);
                }
                while (!list_empty(&unconf_str_hashtbl[i])) {
                        clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
 -                      expire_client(clp);
 +                      destroy_client(clp);
                }
        }
        INIT_LIST_HEAD(&reaplist);
diff --combined fs/nfsd/vfs.c
index e76a17e003c50549e47c692ae79dcd4dd486f2bb,3f67b8e122515302709e606ef38881ba01aae581..c120b48ec305bed3b15aec207b1dd2dac57e952b
@@@ -480,7 -480,7 +480,7 @@@ set_nfsv4_acl_one(struct dentry *dentry
        if (buf == NULL)
                goto out;
  
-       len = posix_acl_to_xattr(pacl, buf, buflen);
+       len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen);
        if (len < 0) {
                error = len;
                goto out;
@@@ -549,7 -549,7 +549,7 @@@ _get_posix_acl(struct dentry *dentry, c
        if (buflen <= 0)
                return ERR_PTR(buflen);
  
-       pacl = posix_acl_from_xattr(buf, buflen);
+       pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen);
        kfree(buf);
        return pacl;
  }
@@@ -1581,7 -1581,7 +1581,7 @@@ nfsd_readlink(struct svc_rqst *rqstp, s
         */
  
        oldfs = get_fs(); set_fs(KERNEL_DS);
 -      host_err = inode->i_op->readlink(path.dentry, buf, *lenp);
 +      host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp);
        set_fs(oldfs);
  
        if (host_err < 0)
@@@ -2264,7 -2264,7 +2264,7 @@@ nfsd_get_posix_acl(struct svc_fh *fhp, 
        if (size < 0)
                return ERR_PTR(size);
  
-       acl = posix_acl_from_xattr(value, size);
+       acl = posix_acl_from_xattr(&init_user_ns, value, size);
        kfree(value);
        return acl;
  }
@@@ -2297,7 -2297,7 +2297,7 @@@ nfsd_set_posix_acl(struct svc_fh *fhp, 
                value = kmalloc(size, GFP_KERNEL);
                if (!value)
                        return -ENOMEM;
-               error = posix_acl_to_xattr(acl, value, size);
+               error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
                if (error < 0)
                        goto getout;
                size = error;