nfs4.1: Add SP4_MACH_CRED write and commit support
authorWeston Andros Adamson <dros@netapp.com>
Tue, 13 Aug 2013 20:37:37 +0000 (16:37 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 5 Sep 2013 14:50:45 +0000 (10:50 -0400)
WRITE and COMMIT can use the machine credential.

If WRITE is supported and COMMIT is not, make all (mach cred) writes FILE_SYNC4.

Signed-off-by: Weston Andros Adamson <dros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/write.c
include/linux/nfs_fs_sb.h

index 3559e899666e6aeb7947cac6ede4641580c4dca4..d2db3ce07d3aba4e7e954a37e9908d48cb389e13 100644 (file)
@@ -269,15 +269,9 @@ is_ds_client(struct nfs_client *clp)
        return clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_DS;
 }
 
-/*
- * Function responsible for determining if an rpc_message should use the
- * machine cred under SP4_MACH_CRED and if so switching the credential and
- * authflavor (using the nfs_client's rpc_clnt which will be krb5i/p).
- * Should be called before rpc_call_sync/rpc_call_async.
- */
-static inline void
-nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
-                  struct rpc_clnt **clntp, struct rpc_message *msg)
+static inline bool
+_nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
+                   struct rpc_clnt **clntp, struct rpc_message *msg)
 {
        struct rpc_cred *newcred = NULL;
        rpc_authflavor_t flavor;
@@ -295,7 +289,37 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
                WARN_ON(flavor != RPC_AUTH_GSS_KRB5I &&
                        flavor != RPC_AUTH_GSS_KRB5P);
                *clntp = clp->cl_rpcclient;
+
+               return true;
        }
+       return false;
+}
+
+/*
+ * Function responsible for determining if an rpc_message should use the
+ * machine cred under SP4_MACH_CRED and if so switching the credential and
+ * authflavor (using the nfs_client's rpc_clnt which will be krb5i/p).
+ * Should be called before rpc_call_sync/rpc_call_async.
+ */
+static inline void
+nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
+                  struct rpc_clnt **clntp, struct rpc_message *msg)
+{
+       _nfs4_state_protect(clp, sp4_mode, clntp, msg);
+}
+
+/*
+ * Special wrapper to nfs4_state_protect for write.
+ * If WRITE can use machine cred but COMMIT cannot, make sure all writes
+ * that use machine cred use NFS_FILE_SYNC.
+ */
+static inline void
+nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
+                        struct rpc_message *msg, struct nfs_write_data *wdata)
+{
+       if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) &&
+           !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags))
+               wdata->args.stable = NFS_FILE_SYNC;
 }
 #else /* CONFIG_NFS_v4_1 */
 static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
@@ -320,6 +344,12 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags,
                   struct rpc_clnt **clntp, struct rpc_message *msg)
 {
 }
+
+static inline void
+nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
+                        struct rpc_message *msg, struct nfs_write_data *wdata)
+{
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
@@ -455,6 +485,8 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
 
 #define nfs4_close_state(a, b) do { } while (0)
 #define nfs4_close_sync(a, b) do { } while (0)
+#define nfs4_state_protect(a, b, c, d) do { } while (0)
+#define nfs4_state_protect_write(a, b, c, d) do { } while (0)
 
 #endif /* CONFIG_NFS_V4 */
 #endif /* __LINUX_FS_NFS_NFS4_FS.H */
index 4818a38f469bf79424769ce3db483b3a0d3b3b71..e3cdfe346ebc1f73a6a38707cb2de0fc1f47a1b6 100644 (file)
@@ -6223,6 +6223,16 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
                        dfprintk(MOUNT, "  stateid mode enabled\n");
                        set_bit(NFS_SP4_MACH_CRED_STATEID, &clp->cl_sp4_flags);
                }
+
+               if (test_bit(OP_WRITE, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  write mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_WRITE, &clp->cl_sp4_flags);
+               }
+
+               if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  commit mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags);
+               }
        }
 
        return 0;
index 379450c8d04b027c7e19a6b11d5f8037f7405fc1..40979e815434bb19d3fbc0b996d4906c0896aedb 100644 (file)
@@ -1022,6 +1022,9 @@ int nfs_initiate_write(struct rpc_clnt *clnt,
                data->args.count,
                (unsigned long long)data->args.offset);
 
+       nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client,
+                                &task_setup_data.rpc_client, &msg, data);
+
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task)) {
                ret = PTR_ERR(task);
@@ -1488,6 +1491,9 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,
 
        dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
 
+       nfs4_state_protect(NFS_SERVER(data->inode)->nfs_client,
+               NFS_SP4_MACH_CRED_COMMIT, &task_setup_data.rpc_client, &msg);
+
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
index 179586555bbefa55b88bca5c550727260bf40b11..e8ff178c3d333560340a89e5bcdab3cc7035df93 100644 (file)
@@ -97,6 +97,8 @@ struct nfs_client {
 #define NFS_SP4_MACH_CRED_CLEANUP  2   /* CLOSE and LOCKU */
 #define NFS_SP4_MACH_CRED_SECINFO  3   /* SECINFO and SECINFO_NO_NAME */
 #define NFS_SP4_MACH_CRED_STATEID  4   /* TEST_STATEID and FREE_STATEID */
+#define NFS_SP4_MACH_CRED_WRITE    5   /* WRITE */
+#define NFS_SP4_MACH_CRED_COMMIT   6   /* COMMIT */
 #endif /* CONFIG_NFS_V4 */
 
 #ifdef CONFIG_NFS_FSCACHE