NFSD: Fix nfs4_verifier memory alignment
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / nfsd / nfs4state.c
index 1b3e2bd..e318964 100644 (file)
@@ -95,6 +95,19 @@ nfs4_lock_state(void)
        mutex_lock(&client_mutex);
 }
 
+static void free_session(struct kref *);
+
+/* Must be called under the client_lock */
+static void nfsd4_put_session_locked(struct nfsd4_session *ses)
+{
+       kref_put(&ses->se_ref, free_session);
+}
+
+static void nfsd4_get_session(struct nfsd4_session *ses)
+{
+       kref_get(&ses->se_ref);
+}
+
 void
 nfs4_unlock_state(void)
 {
@@ -609,12 +622,20 @@ hash_sessionid(struct nfs4_sessionid *sessionid)
        return sid->sequence % SESSION_HASH_SIZE;
 }
 
+#ifdef NFSD_DEBUG
 static inline void
 dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
 {
        u32 *ptr = (u32 *)(&sessionid->data[0]);
        dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
 }
+#else
+static inline void
+dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
+{
+}
+#endif
+
 
 static void
 gen_sessionid(struct nfsd4_session *ses)
@@ -836,11 +857,12 @@ static void nfsd4_del_conns(struct nfsd4_session *s)
        spin_unlock(&clp->cl_lock);
 }
 
-void free_session(struct kref *kref)
+static void free_session(struct kref *kref)
 {
        struct nfsd4_session *ses;
        int mem;
 
+       BUG_ON(!spin_is_locked(&client_lock));
        ses = container_of(kref, struct nfsd4_session, se_ref);
        nfsd4_del_conns(ses);
        spin_lock(&nfsd_drc_lock);
@@ -851,6 +873,13 @@ void free_session(struct kref *kref)
        kfree(ses);
 }
 
+void nfsd4_put_session(struct nfsd4_session *ses)
+{
+       spin_lock(&client_lock);
+       nfsd4_put_session_locked(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)
 {
        struct nfsd4_session *new;
@@ -898,7 +927,9 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
        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) {
@@ -1010,12 +1041,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 static inline void
 free_client(struct nfs4_client *clp)
 {
+       BUG_ON(!spin_is_locked(&client_lock));
        while (!list_empty(&clp->cl_sessions)) {
                struct nfsd4_session *ses;
                ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
                                se_perclnt);
                list_del(&ses->se_perclnt);
-               nfsd4_put_session(ses);
+               nfsd4_put_session_locked(ses);
        }
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
@@ -1142,12 +1174,12 @@ static void gen_clid(struct nfs4_client *clp)
 
 static void gen_confirm(struct nfs4_client *clp)
 {
+       __be32 verf[2];
        static u32 i;
-       u32 *p;
 
-       p = (u32 *)clp->cl_confirm.data;
-       *p++ = get_seconds();
-       *p++ = i++;
+       verf[0] = (__be32)get_seconds();
+       verf[1] = (__be32)i++;
+       memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
 static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
@@ -1184,7 +1216,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        if (princ) {
                clp->cl_principal = kstrdup(princ, GFP_KERNEL);
                if (clp->cl_principal == NULL) {
+                       spin_lock(&client_lock);
                        free_client(clp);
+                       spin_unlock(&client_lock);
                        return NULL;
                }
        }
@@ -1812,9 +1846,10 @@ nfsd4_destroy_session(struct svc_rqst *r,
        nfsd4_probe_callback_sync(ses->se_client);
        nfs4_unlock_state();
 
+       spin_lock(&client_lock);
        nfsd4_del_conns(ses);
-
-       nfsd4_put_session(ses);
+       nfsd4_put_session_locked(ses);
+       spin_unlock(&client_lock);
        status = nfs_ok;
 out:
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -2951,6 +2986,24 @@ out_no_deleg:
        goto out;
 }
 
+static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
+                                       struct nfs4_delegation *dp)
+{
+       if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
+           dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+               open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+               open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
+       } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
+                  dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+               open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+               open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
+       }
+       /* Otherwise the client must be confused wanting a delegation
+        * it already has, therefore we don't return
+        * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
+        */
+}
+
 /*
  * called with nfs4_lock_state() held.
  */
@@ -3035,21 +3088,8 @@ nodeleg:
 out:
        /* 4.1 client trying to upgrade/downgrade delegation? */
        if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
-           open->op_deleg_want) {
-               if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
-                   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
-                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
-                       open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
-               } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
-                          dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
-                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
-                       open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
-               }
-               /* Otherwise the client must be confused wanting a delegation
-                * it already has, therefore we don't return
-                * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
-                */
-       }
+           open->op_deleg_want)
+               nfsd4_deleg_xgrade_none_ext(open, dp);
 
        if (fp)
                put_nfs4_file(fp);