|
@@ -5984,6 +5984,157 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This operation also signals the server that this client is
|
|
|
+ * performing migration recovery. The server can stop returning
|
|
|
+ * NFS4ERR_LEASE_MOVED to this client. A RENEW operation is
|
|
|
+ * appended to this compound to identify the client ID which is
|
|
|
+ * performing recovery.
|
|
|
+ */
|
|
|
+static int _nfs40_proc_get_locations(struct inode *inode,
|
|
|
+ struct nfs4_fs_locations *locations,
|
|
|
+ struct page *page, struct rpc_cred *cred)
|
|
|
+{
|
|
|
+ struct nfs_server *server = NFS_SERVER(inode);
|
|
|
+ struct rpc_clnt *clnt = server->client;
|
|
|
+ u32 bitmask[2] = {
|
|
|
+ [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
|
|
|
+ };
|
|
|
+ struct nfs4_fs_locations_arg args = {
|
|
|
+ .clientid = server->nfs_client->cl_clientid,
|
|
|
+ .fh = NFS_FH(inode),
|
|
|
+ .page = page,
|
|
|
+ .bitmask = bitmask,
|
|
|
+ .migration = 1, /* skip LOOKUP */
|
|
|
+ .renew = 1, /* append RENEW */
|
|
|
+ };
|
|
|
+ struct nfs4_fs_locations_res res = {
|
|
|
+ .fs_locations = locations,
|
|
|
+ .migration = 1,
|
|
|
+ .renew = 1,
|
|
|
+ };
|
|
|
+ struct rpc_message msg = {
|
|
|
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
|
|
|
+ .rpc_argp = &args,
|
|
|
+ .rpc_resp = &res,
|
|
|
+ .rpc_cred = cred,
|
|
|
+ };
|
|
|
+ unsigned long now = jiffies;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ nfs_fattr_init(&locations->fattr);
|
|
|
+ locations->server = server;
|
|
|
+ locations->nlocations = 0;
|
|
|
+
|
|
|
+ nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
|
|
|
+ nfs4_set_sequence_privileged(&args.seq_args);
|
|
|
+ status = nfs4_call_sync_sequence(clnt, server, &msg,
|
|
|
+ &args.seq_args, &res.seq_res);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ renew_lease(server, now);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_NFS_V4_1
|
|
|
+
|
|
|
+/*
|
|
|
+ * This operation also signals the server that this client is
|
|
|
+ * performing migration recovery. The server can stop asserting
|
|
|
+ * SEQ4_STATUS_LEASE_MOVED for this client. The client ID
|
|
|
+ * performing this operation is identified in the SEQUENCE
|
|
|
+ * operation in this compound.
|
|
|
+ *
|
|
|
+ * When the client supports GETATTR(fs_locations_info), it can
|
|
|
+ * be plumbed in here.
|
|
|
+ */
|
|
|
+static int _nfs41_proc_get_locations(struct inode *inode,
|
|
|
+ struct nfs4_fs_locations *locations,
|
|
|
+ struct page *page, struct rpc_cred *cred)
|
|
|
+{
|
|
|
+ struct nfs_server *server = NFS_SERVER(inode);
|
|
|
+ struct rpc_clnt *clnt = server->client;
|
|
|
+ u32 bitmask[2] = {
|
|
|
+ [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
|
|
|
+ };
|
|
|
+ struct nfs4_fs_locations_arg args = {
|
|
|
+ .fh = NFS_FH(inode),
|
|
|
+ .page = page,
|
|
|
+ .bitmask = bitmask,
|
|
|
+ .migration = 1, /* skip LOOKUP */
|
|
|
+ };
|
|
|
+ struct nfs4_fs_locations_res res = {
|
|
|
+ .fs_locations = locations,
|
|
|
+ .migration = 1,
|
|
|
+ };
|
|
|
+ struct rpc_message msg = {
|
|
|
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
|
|
|
+ .rpc_argp = &args,
|
|
|
+ .rpc_resp = &res,
|
|
|
+ .rpc_cred = cred,
|
|
|
+ };
|
|
|
+ int status;
|
|
|
+
|
|
|
+ nfs_fattr_init(&locations->fattr);
|
|
|
+ locations->server = server;
|
|
|
+ locations->nlocations = 0;
|
|
|
+
|
|
|
+ nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
|
|
|
+ nfs4_set_sequence_privileged(&args.seq_args);
|
|
|
+ status = nfs4_call_sync_sequence(clnt, server, &msg,
|
|
|
+ &args.seq_args, &res.seq_res);
|
|
|
+ if (status == NFS4_OK &&
|
|
|
+ res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
|
|
|
+ status = -NFS4ERR_LEASE_MOVED;
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* CONFIG_NFS_V4_1 */
|
|
|
+
|
|
|
+/**
|
|
|
+ * nfs4_proc_get_locations - discover locations for a migrated FSID
|
|
|
+ * @inode: inode on FSID that is migrating
|
|
|
+ * @locations: result of query
|
|
|
+ * @page: buffer
|
|
|
+ * @cred: credential to use for this operation
|
|
|
+ *
|
|
|
+ * Returns NFS4_OK on success, a negative NFS4ERR status code if the
|
|
|
+ * operation failed, or a negative errno if a local error occurred.
|
|
|
+ *
|
|
|
+ * On success, "locations" is filled in, but if the server has
|
|
|
+ * no locations information, NFS_ATTR_FATTR_V4_LOCATIONS is not
|
|
|
+ * asserted.
|
|
|
+ *
|
|
|
+ * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
|
|
|
+ * from this client that require migration recovery.
|
|
|
+ */
|
|
|
+int nfs4_proc_get_locations(struct inode *inode,
|
|
|
+ struct nfs4_fs_locations *locations,
|
|
|
+ struct page *page, struct rpc_cred *cred)
|
|
|
+{
|
|
|
+ struct nfs_server *server = NFS_SERVER(inode);
|
|
|
+ struct nfs_client *clp = server->nfs_client;
|
|
|
+ const struct nfs4_mig_recovery_ops *ops =
|
|
|
+ clp->cl_mvops->mig_recovery_ops;
|
|
|
+ struct nfs4_exception exception = { };
|
|
|
+ int status;
|
|
|
+
|
|
|
+ dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
|
|
|
+ (unsigned long long)server->fsid.major,
|
|
|
+ (unsigned long long)server->fsid.minor,
|
|
|
+ clp->cl_hostname);
|
|
|
+ nfs_display_fhandle(NFS_FH(inode), __func__);
|
|
|
+
|
|
|
+ do {
|
|
|
+ status = ops->get_locations(inode, locations, page, cred);
|
|
|
+ if (status != -NFS4ERR_DELAY)
|
|
|
+ break;
|
|
|
+ nfs4_handle_exception(server, status, &exception);
|
|
|
+ } while (exception.retry);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* If 'use_integrity' is true and the state managment nfs_client
|
|
|
* cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
|
|
@@ -7882,10 +8033,12 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
|
|
|
#endif
|
|
|
|
|
|
static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
|
|
|
+ .get_locations = _nfs40_proc_get_locations,
|
|
|
};
|
|
|
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
|
static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = {
|
|
|
+ .get_locations = _nfs41_proc_get_locations,
|
|
|
};
|
|
|
#endif /* CONFIG_NFS_V4_1 */
|
|
|
|