Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2013 17:17:13 +0000 (10:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2013 17:17:13 +0000 (10:17 -0700)
Pull nfsd changes from Bruce Fields:
 "Changes this time include:

   - 4.1 enabled on the server by default: the last 4.1-specific issues
     I know of are fixed, so we're not going to find the rest of the
     bugs without more exposure.
   - Experimental support for NFSv4.2 MAC Labeling (to allow running
     selinux over NFS), from Dave Quigley.
   - Fixes for some delicate cache/upcall races that could cause rare
     server hangs; thanks to Neil Brown and Bodo Stroesser for extreme
     debugging persistence.
   - Fixes for some bugs found at the recent NFS bakeathon, mostly v4
     and v4.1-specific, but also a generic bug handling fragmented rpc
     calls"

* 'for-3.11' of git://linux-nfs.org/~bfields/linux: (31 commits)
  nfsd4: support minorversion 1 by default
  nfsd4: allow destroy_session over destroyed session
  svcrpc: fix failures to handle -1 uid's
  sunrpc: Don't schedule an upcall on a replaced cache entry.
  net/sunrpc: xpt_auth_cache should be ignored when expired.
  sunrpc/cache: ensure items removed from cache do not have pending upcalls.
  sunrpc/cache: use cache_fresh_unlocked consistently and correctly.
  sunrpc/cache: remove races with queuing an upcall.
  nfsd4: return delegation immediately if lease fails
  nfsd4: do not throw away 4.1 lock state on last unlock
  nfsd4: delegation-based open reclaims should bypass permissions
  svcrpc: don't error out on small tcp fragment
  svcrpc: fix handling of too-short rpc's
  nfsd4: minor read_buf cleanup
  nfsd4: fix decoding of compounds across page boundaries
  nfsd4: clean up nfs4_open_delegation
  NFSD: Don't give out read delegations on creates
  nfsd4: allow client to send no cb_sec flavors
  nfsd4: fail attempts to request gss on the backchannel
  nfsd4: implement minimal SP4_MACH_CRED
  ...

1  2 
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/xprtsock.c
security/capability.c

diff --combined fs/nfsd/nfs4state.c
@@@ -97,19 -97,20 +97,20 @@@ nfs4_lock_state(void
  
  static void free_session(struct nfsd4_session *);
  
void nfsd4_put_session(struct nfsd4_session *ses)
static bool is_session_dead(struct nfsd4_session *ses)
  {
-       atomic_dec(&ses->se_ref);
+       return ses->se_flags & NFS4_SESSION_DEAD;
  }
  
static bool is_session_dead(struct nfsd4_session *ses)
void nfsd4_put_session(struct nfsd4_session *ses)
  {
-       return ses->se_flags & NFS4_SESSION_DEAD;
+       if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
+               free_session(ses);
  }
  
- static __be32 mark_session_dead_locked(struct nfsd4_session *ses)
+ static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
  {
-       if (atomic_read(&ses->se_ref))
+       if (atomic_read(&ses->se_ref) > ref_held_by_me)
                return nfserr_jukebox;
        ses->se_flags |= NFS4_SESSION_DEAD;
        return nfs_ok;
@@@ -364,19 -365,12 +365,12 @@@ static struct nfs4_ol_stateid * nfs4_al
  }
  
  static struct nfs4_delegation *
- alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
+ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
  {
        struct nfs4_delegation *dp;
        struct nfs4_file *fp = stp->st_file;
  
        dprintk("NFSD alloc_init_deleg\n");
-       /*
-        * Major work on the lease subsystem (for example, to support
-        * calbacks on stat) will be required before we can support
-        * write delegations properly.
-        */
-       if (type != NFS4_OPEN_DELEGATE_READ)
-               return NULL;
        if (fp->fi_had_conflict)
                return NULL;
        if (num_delegations > max_delegations)
        INIT_LIST_HEAD(&dp->dl_recall_lru);
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       dp->dl_type = type;
+       dp->dl_type = NFS4_OPEN_DELEGATE_READ;
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
@@@ -1188,6 -1182,9 +1182,9 @@@ static int copy_cred(struct svc_cred *t
        target->cr_gid = source->cr_gid;
        target->cr_group_info = source->cr_group_info;
        get_group_info(target->cr_group_info);
+       target->cr_gss_mech = source->cr_gss_mech;
+       if (source->cr_gss_mech)
+               gss_mech_get(source->cr_gss_mech);
        return 0;
  }
  
@@@ -1262,6 -1259,31 +1259,31 @@@ same_creds(struct svc_cred *cr1, struc
        return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
  }
  
+ static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
+ {
+       struct svc_cred *cr = &rqstp->rq_cred;
+       u32 service;
+       service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
+       return service == RPC_GSS_SVC_INTEGRITY ||
+              service == RPC_GSS_SVC_PRIVACY;
+ }
+ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
+ {
+       struct svc_cred *cr = &rqstp->rq_cred;
+       if (!cl->cl_mach_cred)
+               return true;
+       if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
+               return false;
+       if (!svc_rqst_integrity_protected(rqstp))
+               return false;
+       if (!cr->cr_principal)
+               return false;
+       return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
+ }
  static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
  {
        static u32 current_clientid = 1;
@@@ -1639,16 -1661,16 +1661,16 @@@ nfsd4_exchange_id(struct svc_rqst *rqst
        if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
                return nfserr_inval;
  
-       /* Currently only support SP4_NONE */
        switch (exid->spa_how) {
+       case SP4_MACH_CRED:
+               if (!svc_rqst_integrity_protected(rqstp))
+                       return nfserr_inval;
        case SP4_NONE:
                break;
        default:                                /* checked by xdr code */
                WARN_ON_ONCE(1);
        case SP4_SSV:
                return nfserr_encr_alg_unsupp;
-       case SP4_MACH_CRED:
-               return nfserr_serverfault;      /* no excuse :-/ */
        }
  
        /* Cases below refer to rfc 5661 section 18.35.4: */
                                status = nfserr_inval;
                                goto out;
                        }
+                       if (!mach_creds_match(conf, rqstp)) {
+                               status = nfserr_wrong_cred;
+                               goto out;
+                       }
                        if (!creds_match) { /* case 9 */
                                status = nfserr_perm;
                                goto out;
@@@ -1709,7 -1735,8 +1735,8 @@@ out_new
                status = nfserr_jukebox;
                goto out;
        }
-       new->cl_minorversion = 1;
+       new->cl_minorversion = cstate->minorversion;
+       new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
  
        gen_clid(new, nn);
        add_to_unconfirmed(new);
@@@ -1839,6 -1866,24 +1866,24 @@@ static __be32 check_backchannel_attrs(s
        return nfs_ok;
  }
  
+ static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
+ {
+       switch (cbs->flavor) {
+       case RPC_AUTH_NULL:
+       case RPC_AUTH_UNIX:
+               return nfs_ok;
+       default:
+               /*
+                * GSS case: the spec doesn't allow us to return this
+                * error.  But it also doesn't allow us not to support
+                * GSS.
+                * I'd rather this fail hard than return some error the
+                * client might think it can already handle:
+                */
+               return nfserr_encr_alg_unsupp;
+       }
+ }
  __be32
  nfsd4_create_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
  
        if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
                return nfserr_inval;
+       status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
+       if (status)
+               return status;
        status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
        if (status)
                return status;
        WARN_ON_ONCE(conf && unconf);
  
        if (conf) {
+               status = nfserr_wrong_cred;
+               if (!mach_creds_match(conf, rqstp))
+                       goto out_free_conn;
                cs_slot = &conf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status == nfserr_replay_cache) {
                        status = nfserr_clid_inuse;
                        goto out_free_conn;
                }
+               status = nfserr_wrong_cred;
+               if (!mach_creds_match(unconf, rqstp))
+                       goto out_free_conn;
                cs_slot = &unconf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status) {
@@@ -1957,7 -2011,11 +2011,11 @@@ __be32 nfsd4_backchannel_ctl(struct svc
  {
        struct nfsd4_session *session = cstate->session;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       __be32 status;
  
+       status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
+       if (status)
+               return status;
        spin_lock(&nn->client_lock);
        session->se_cb_prog = bc->bc_cb_program;
        session->se_cb_sec = bc->bc_cb_sec;
@@@ -1986,6 -2044,9 +2044,9 @@@ __be32 nfsd4_bind_conn_to_session(struc
        status = nfserr_badsession;
        if (!session)
                goto out;
+       status = nfserr_wrong_cred;
+       if (!mach_creds_match(session->se_client, rqstp))
+               goto out;
        status = nfsd4_map_bcts_dir(&bcts->dir);
        if (status)
                goto out;
@@@ -2014,6 -2075,7 +2075,7 @@@ nfsd4_destroy_session(struct svc_rqst *
  {
        struct nfsd4_session *ses;
        __be32 status;
+       int ref_held_by_me = 0;
        struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
  
        nfs4_lock_state();
        if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
                if (!nfsd4_last_compound_op(r))
                        goto out;
+               ref_held_by_me++;
        }
        dump_sessionid(__func__, &sessionid->sessionid);
        spin_lock(&nn->client_lock);
        status = nfserr_badsession;
        if (!ses)
                goto out_client_lock;
-       status = mark_session_dead_locked(ses);
-       if (status)
+       status = nfserr_wrong_cred;
+       if (!mach_creds_match(ses->se_client, r))
                goto out_client_lock;
+       nfsd4_get_session_locked(ses);
+       status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
+       if (status)
+               goto out_put_session;
        unhash_session(ses);
        spin_unlock(&nn->client_lock);
  
        nfsd4_probe_callback_sync(ses->se_client);
  
        spin_lock(&nn->client_lock);
-       free_session(ses);
        status = nfs_ok;
+ out_put_session:
+       nfsd4_put_session(ses);
  out_client_lock:
        spin_unlock(&nn->client_lock);
  out:
@@@ -2058,26 -2126,31 +2126,31 @@@ static struct nfsd4_conn *__nfsd4_find_
        return NULL;
  }
  
- static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
+ static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
  {
        struct nfs4_client *clp = ses->se_client;
        struct nfsd4_conn *c;
+       __be32 status = nfs_ok;
        int ret;
  
        spin_lock(&clp->cl_lock);
        c = __nfsd4_find_conn(new->cn_xprt, ses);
-       if (c) {
-               spin_unlock(&clp->cl_lock);
-               free_conn(new);
-               return;
-       }
+       if (c)
+               goto out_free;
+       status = nfserr_conn_not_bound_to_session;
+       if (clp->cl_mach_cred)
+               goto out_free;
        __nfsd4_hash_conn(new, ses);
        spin_unlock(&clp->cl_lock);
        ret = nfsd4_register_conn(new);
        if (ret)
                /* oops; xprt is already down: */
                nfsd4_conn_lost(&new->cn_xpt_user);
-       return;
+       return nfs_ok;
+ out_free:
+       spin_unlock(&clp->cl_lock);
+       free_conn(new);
+       return status;
  }
  
  static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
@@@ -2169,8 -2242,10 +2242,10 @@@ nfsd4_sequence(struct svc_rqst *rqstp
        if (status)
                goto out_put_session;
  
-       nfsd4_sequence_check_conn(conn, session);
+       status = nfsd4_sequence_check_conn(conn, session);
        conn = NULL;
+       if (status)
+               goto out_put_session;
  
        /* Success! bump slot seqid */
        slot->sl_seqid = seq->seqid;
@@@ -2232,7 -2307,10 +2307,10 @@@ nfsd4_destroy_clientid(struct svc_rqst 
                status = nfserr_stale_clientid;
                goto out;
        }
+       if (!mach_creds_match(clp, rqstp)) {
+               status = nfserr_wrong_cred;
+               goto out;
+       }
        expire_client(clp);
  out:
        nfs4_unlock_state();
@@@ -2645,13 -2723,13 +2723,13 @@@ static void nfsd_break_one_deleg(struc
  
        list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
  
 -      /* only place dl_time is set. protected by lock_flocks*/
 +      /* Only place dl_time is set; protected by i_lock: */
        dp->dl_time = get_seconds();
  
        nfsd4_cb_recall(dp);
  }
  
 -/* Called from break_lease() with lock_flocks() held. */
 +/* Called from break_lease() with i_lock held. */
  static void nfsd_break_deleg_cb(struct file_lock *fl)
  {
        struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
@@@ -2940,13 -3018,13 +3018,13 @@@ static struct file_lock *nfs4_alloc_ini
        return fl;
  }
  
- static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
+ static int nfs4_setlease(struct nfs4_delegation *dp)
  {
        struct nfs4_file *fp = dp->dl_file;
        struct file_lock *fl;
        int status;
  
-       fl = nfs4_alloc_init_lease(dp, flag);
+       fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
        if (!fl)
                return -ENOMEM;
        fl->fl_file = find_readable_file(fp);
        return 0;
  }
  
- static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
+ static int nfs4_set_delegation(struct nfs4_delegation *dp)
  {
        struct nfs4_file *fp = dp->dl_file;
  
        if (!fp->fi_lease)
-               return nfs4_setlease(dp, flag);
+               return nfs4_setlease(dp);
        spin_lock(&recall_lock);
        if (fp->fi_had_conflict) {
                spin_unlock(&recall_lock);
@@@ -3005,6 -3083,9 +3083,9 @@@ static void nfsd4_open_deleg_none_ext(s
  
  /*
   * Attempt to hand out a delegation.
+  *
+  * Note we don't support write delegations, and won't until the vfs has
+  * proper support for them.
   */
  static void
  nfs4_open_delegation(struct net *net, struct svc_fh *fh,
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
        int cb_up;
-       int status = 0, flag = 0;
+       int status = 0;
  
        cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
-       flag = NFS4_OPEN_DELEGATE_NONE;
        open->op_recall = 0;
        switch (open->op_claim_type) {
                case NFS4_OPEN_CLAIM_PREVIOUS:
                        if (!cb_up)
                                open->op_recall = 1;
-                       flag = open->op_delegate_type;
-                       if (flag == NFS4_OPEN_DELEGATE_NONE)
-                               goto out;
+                       if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
+                               goto out_no_deleg;
                        break;
                case NFS4_OPEN_CLAIM_NULL:
-                       /* Let's not give out any delegations till everyone's
-                        * had the chance to reclaim theirs.... */
+                       /*
+                        * Let's not give out any delegations till everyone's
+                        * had the chance to reclaim theirs....
+                        */
                        if (locks_in_grace(net))
-                               goto out;
+                               goto out_no_deleg;
                        if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
-                               goto out;
+                               goto out_no_deleg;
+                       /*
+                        * Also, if the file was opened for write or
+                        * create, there's a good chance the client's
+                        * about to write to it, resulting in an
+                        * immediate recall (since we don't support
+                        * write delegations):
+                        */
                        if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
-                               flag = NFS4_OPEN_DELEGATE_WRITE;
-                       else
-                               flag = NFS4_OPEN_DELEGATE_READ;
+                               goto out_no_deleg;
+                       if (open->op_create == NFS4_OPEN_CREATE)
+                               goto out_no_deleg;
                        break;
                default:
-                       goto out;
+                       goto out_no_deleg;
        }
-       dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
+       dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
        if (dp == NULL)
                goto out_no_deleg;
-       status = nfs4_set_delegation(dp, flag);
+       status = nfs4_set_delegation(dp);
        if (status)
                goto out_free;
  
  
        dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
                STATEID_VAL(&dp->dl_stid.sc_stateid));
- out:
-       open->op_delegate_type = flag;
-       if (flag == NFS4_OPEN_DELEGATE_NONE) {
-               if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
-                   open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-                       dprintk("NFSD: WARNING: refusing delegation reclaim\n");
-               /* 4.1 client asking for a delegation? */
-               if (open->op_deleg_want)
-                       nfsd4_open_deleg_none_ext(open, status);
-       }
+       open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
        return;
  out_free:
        unhash_stid(&dp->dl_stid);
        nfs4_put_delegation(dp);
  out_no_deleg:
-       flag = NFS4_OPEN_DELEGATE_NONE;
-       goto out;
+       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
+       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
+           open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
+               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
+               open->op_recall = 1;
+       }
+       /* 4.1 client asking for a delegation? */
+       if (open->op_deleg_want)
+               nfsd4_open_deleg_none_ext(open, status);
+       return;
  }
  
  static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
@@@ -3427,7 -3513,7 +3513,7 @@@ grace_disallows_io(struct net *net, str
  /* Returns true iff a is later than b: */
  static bool stateid_generation_after(stateid_t *a, stateid_t *b)
  {
-       return (s32)a->si_generation - (s32)b->si_generation > 0;
+       return (s32)(a->si_generation - b->si_generation) > 0;
  }
  
  static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
@@@ -4435,7 -4521,6 +4521,6 @@@ __be3
  nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            struct nfsd4_locku *locku)
  {
-       struct nfs4_lockowner *lo;
        struct nfs4_ol_stateid *stp;
        struct file *filp = NULL;
        struct file_lock *file_lock = NULL;
                status = nfserr_jukebox;
                goto out;
        }
-       lo = lockowner(stp->st_stateowner);
        locks_init_lock(file_lock);
        file_lock->fl_type = F_UNLCK;
-       file_lock->fl_owner = (fl_owner_t)lo;
+       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;
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
  
-       if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) {
-               WARN_ON_ONCE(cstate->replay_owner);
-               release_lockowner(lo);
-       }
  out:
        nfsd4_bump_seqid(cstate, status);
        if (!cstate->replay_owner)
@@@ -4520,7 -4599,7 +4599,7 @@@ check_for_locks(struct nfs4_file *filp
        struct inode *inode = filp->fi_inode;
        int status = 0;
  
 -      lock_flocks();
 +      spin_lock(&inode->i_lock);
        for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
                if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
                        status = 1;
                }
        }
  out:
 -      unlock_flocks();
 +      spin_unlock(&inode->i_lock);
        return status;
  }
  
diff --combined fs/nfsd/vfs.c
@@@ -28,6 -28,7 +28,7 @@@
  #include <asm/uaccess.h>
  #include <linux/exportfs.h>
  #include <linux/writeback.h>
+ #include <linux/security.h>
  
  #ifdef CONFIG_NFSD_V3
  #include "xdr3.h"
@@@ -621,6 -622,33 +622,33 @@@ int nfsd4_is_junction(struct dentry *de
                return 0;
        return 1;
  }
+ #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct xdr_netobj *label)
+ {
+       __be32 error;
+       int host_error;
+       struct dentry *dentry;
+       error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+       if (error)
+               return error;
+       dentry = fhp->fh_dentry;
+       mutex_lock(&dentry->d_inode->i_mutex);
+       host_error = security_inode_setsecctx(dentry, label->data, label->len);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+       return nfserrno(host_error);
+ }
+ #else
+ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct xdr_netobj *label)
+ {
+       return nfserr_notsupp;
+ }
+ #endif
  #endif /* defined(CONFIG_NFSD_V4) */
  
  #ifdef CONFIG_NFSD_V3
@@@ -1912,7 -1940,6 +1940,7 @@@ struct buffered_dirent 
  };
  
  struct readdir_data {
 +      struct dir_context ctx;
        char            *dirent;
        size_t          used;
        int             full;
@@@ -1944,15 -1971,13 +1972,15 @@@ static int nfsd_buffered_filldir(void *
  static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
                                    struct readdir_cd *cdp, loff_t *offsetp)
  {
 -      struct readdir_data buf;
        struct buffered_dirent *de;
        int host_err;
        int size;
        loff_t offset;
 +      struct readdir_data buf = {
 +              .ctx.actor = nfsd_buffered_filldir,
 +              .dirent = (void *)__get_free_page(GFP_KERNEL)
 +      };
  
 -      buf.dirent = (void *)__get_free_page(GFP_KERNEL);
        if (!buf.dirent)
                return nfserrno(-ENOMEM);
  
                buf.used = 0;
                buf.full = 0;
  
 -              host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
 +              host_err = iterate_dir(file, &buf.ctx);
                if (buf.full)
                        host_err = 0;
  
@@@ -377,8 -377,7 +377,7 @@@ rsc_init(struct cache_head *cnew, struc
        new->handle.data = tmp->handle.data;
        tmp->handle.data = NULL;
        new->mechctx = NULL;
-       new->cred.cr_group_info = NULL;
-       new->cred.cr_principal = NULL;
+       init_svc_cred(&new->cred);
  }
  
  static void
@@@ -392,9 -391,7 +391,7 @@@ update_rsc(struct cache_head *cnew, str
        memset(&new->seqdata, 0, sizeof(new->seqdata));
        spin_lock_init(&new->seqdata.sd_lock);
        new->cred = tmp->cred;
-       tmp->cred.cr_group_info = NULL;
-       new->cred.cr_principal = tmp->cred.cr_principal;
-       tmp->cred.cr_principal = NULL;
+       init_svc_cred(&tmp->cred);
  }
  
  static struct cache_head *
@@@ -487,7 -484,7 +484,7 @@@ static int rsc_parse(struct cache_detai
                len = qword_get(&mesg, buf, mlen);
                if (len < 0)
                        goto out;
-               gm = gss_mech_get_by_name(buf);
+               gm = rsci.cred.cr_gss_mech = gss_mech_get_by_name(buf);
                status = -EOPNOTSUPP;
                if (!gm)
                        goto out;
        rscp = rsc_update(cd, &rsci, rscp);
        status = 0;
  out:
-       gss_mech_put(gm);
        rsc_free(&rsci);
        if (rscp)
                cache_put(&rscp->h, cd);
@@@ -1330,7 -1326,7 +1326,7 @@@ static int wait_for_gss_proxy(struct ne
  static ssize_t write_gssp(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
  {
 -      struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
 +      struct net *net = PDE_DATA(file_inode(file));
        char tbuf[20];
        unsigned long i;
        int res;
  static ssize_t read_gssp(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
  {
 -      struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
 +      struct net *net = PDE_DATA(file_inode(file));
        unsigned long p = *ppos;
        char tbuf[10];
        size_t len;
diff --combined net/sunrpc/xprtsock.c
@@@ -87,7 -87,7 +87,7 @@@ static struct ctl_table_header *sunrpc_
   * FIXME: changing the UDP slot table size should also resize the UDP
   *        socket buffers for existing UDP transports
   */
 -static ctl_table xs_tunables_table[] = {
 +static struct ctl_table xs_tunables_table[] = {
        {
                .procname       = "udp_slot_table_entries",
                .data           = &xprt_udp_slot_table_entries,
        { },
  };
  
 -static ctl_table sunrpc_table[] = {
 +static struct ctl_table sunrpc_table[] = {
        {
                .procname       = "sunrpc",
                .mode           = 0555,
@@@ -2534,7 -2534,6 +2534,6 @@@ static struct rpc_xprt_ops bc_tcp_ops 
        .reserve_xprt           = xprt_reserve_xprt,
        .release_xprt           = xprt_release_xprt,
        .alloc_slot             = xprt_alloc_slot,
-       .rpcbind                = xs_local_rpcbind,
        .buf_alloc              = bc_malloc,
        .buf_free               = bc_free,
        .send_request           = bc_send_request,
diff --combined security/capability.c
@@@ -91,10 -91,7 +91,10 @@@ static int cap_sb_pivotroot(struct pat
  }
  
  static int cap_sb_set_mnt_opts(struct super_block *sb,
 -                             struct security_mnt_opts *opts)
 +                             struct security_mnt_opts *opts,
 +                             unsigned long kern_flags,
 +                             unsigned long *set_kern_flags)
 +
  {
        if (unlikely(opts->num_mnt_opts))
                return -EOPNOTSUPP;
@@@ -112,13 -109,6 +112,13 @@@ static int cap_sb_parse_opts_str(char *
        return 0;
  }
  
 +static int cap_dentry_init_security(struct dentry *dentry, int mode,
 +                                      struct qstr *name, void **ctx,
 +                                      u32 *ctxlen)
 +{
 +      return 0;
 +}
 +
  static int cap_inode_alloc_security(struct inode *inode)
  {
        return 0;
@@@ -826,11 -816,6 +826,11 @@@ static int cap_setprocattr(struct task_
        return -EINVAL;
  }
  
 +static int cap_ismaclabel(const char *name)
 +{
 +      return 0;
 +}
 +
  static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
  {
        return -EOPNOTSUPP;
@@@ -858,7 -843,7 +858,7 @@@ static int cap_inode_setsecctx(struct d
  
  static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
  {
-       return 0;
+       return -EOPNOTSUPP;
  }
  #ifdef CONFIG_KEYS
  static int cap_key_alloc(struct key *key, const struct cred *cred,
@@@ -946,7 -931,6 +946,7 @@@ void __init security_fixup_ops(struct s
        set_to_cap_if_null(ops, sb_set_mnt_opts);
        set_to_cap_if_null(ops, sb_clone_mnt_opts);
        set_to_cap_if_null(ops, sb_parse_opts_str);
 +      set_to_cap_if_null(ops, dentry_init_security);
        set_to_cap_if_null(ops, inode_alloc_security);
        set_to_cap_if_null(ops, inode_free_security);
        set_to_cap_if_null(ops, inode_init_security);
        set_to_cap_if_null(ops, d_instantiate);
        set_to_cap_if_null(ops, getprocattr);
        set_to_cap_if_null(ops, setprocattr);
 +      set_to_cap_if_null(ops, ismaclabel);
        set_to_cap_if_null(ops, secid_to_secctx);
        set_to_cap_if_null(ops, secctx_to_secid);
        set_to_cap_if_null(ops, release_secctx);