Skip to content

Commit 7472595

Browse files
scottmayhewJ. Bruce Fields
authored and
J. Bruce Fields
committed
nfsd: un-deprecate nfsdcld
When nfsdcld was released, it was quickly deprecated in favor of the nfsdcltrack usermodehelper, so as to not require another running daemon. That prevents NFSv4 clients from reclaiming locks from nfsd's running in containers, since neither nfsdcltrack nor the legacy client tracking code work in containers. This commit un-deprecates the use of nfsdcld, with one twist: we will populate the reclaim_str_hashtbl on startup. During client tracking initialization, do an upcall ("GraceStart") to nfsdcld to get a list of clients from the database. nfsdcld will do one downcall with a status of -EINPROGRESS for each client record in the database, which in turn will cause an nfs4_client_reclaim to be added to the reclaim_str_hashtbl. When complete, nfsdcld will do a final downcall with a status of 0. This will save nfsd from having to do an upcall to the daemon during nfs4_check_open_reclaim() processing. Even though nfsdcld was quickly deprecated, there is a very small chance of old nfsdcld daemons running in the wild. These will respond to the new "GraceStart" upcall with -EOPNOTSUPP, in which case we will log a message and fall back to the original nfsdcld tracking ops (now called nfsd4_cld_tracking_ops_v0). Signed-off-by: Scott Mayhew <smayhew@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent 6b18910 commit 7472595

File tree

2 files changed

+218
-8
lines changed

2 files changed

+218
-8
lines changed

fs/nfsd/nfs4recover.c

+217-8
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,34 @@ cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
779779
return ret;
780780
}
781781

782+
static ssize_t
783+
__cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg,
784+
struct nfsd_net *nn)
785+
{
786+
uint8_t cmd;
787+
struct xdr_netobj name;
788+
uint16_t namelen;
789+
790+
if (get_user(cmd, &cmsg->cm_cmd)) {
791+
dprintk("%s: error when copying cmd from userspace", __func__);
792+
return -EFAULT;
793+
}
794+
if (cmd == Cld_GraceStart) {
795+
if (get_user(namelen, &cmsg->cm_u.cm_name.cn_len))
796+
return -EFAULT;
797+
name.data = memdup_user(&cmsg->cm_u.cm_name.cn_id, namelen);
798+
if (IS_ERR_OR_NULL(name.data))
799+
return -EFAULT;
800+
name.len = namelen;
801+
if (!nfs4_client_to_reclaim(name, nn)) {
802+
kfree(name.data);
803+
return -EFAULT;
804+
}
805+
return sizeof(*cmsg);
806+
}
807+
return -EFAULT;
808+
}
809+
782810
static ssize_t
783811
cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
784812
{
@@ -788,6 +816,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
788816
struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
789817
nfsd_net_id);
790818
struct cld_net *cn = nn->cld_net;
819+
int16_t status;
791820

792821
if (mlen != sizeof(*cmsg)) {
793822
dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
@@ -801,13 +830,24 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
801830
return -EFAULT;
802831
}
803832

833+
/*
834+
* copy the status so we know whether to remove the upcall from the
835+
* list (for -EINPROGRESS, we just want to make sure the xid is
836+
* valid, not remove the upcall from the list)
837+
*/
838+
if (get_user(status, &cmsg->cm_status)) {
839+
dprintk("%s: error when copying status from userspace", __func__);
840+
return -EFAULT;
841+
}
842+
804843
/* walk the list and find corresponding xid */
805844
cup = NULL;
806845
spin_lock(&cn->cn_lock);
807846
list_for_each_entry(tmp, &cn->cn_list, cu_list) {
808847
if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
809848
cup = tmp;
810-
list_del_init(&cup->cu_list);
849+
if (status != -EINPROGRESS)
850+
list_del_init(&cup->cu_list);
811851
break;
812852
}
813853
}
@@ -819,6 +859,9 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
819859
return -EINVAL;
820860
}
821861

862+
if (status == -EINPROGRESS)
863+
return __cld_pipe_inprogress_downcall(cmsg, nn);
864+
822865
if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
823866
return -EFAULT;
824867

@@ -1065,9 +1108,14 @@ nfsd4_cld_remove(struct nfs4_client *clp)
10651108
"record from stable storage: %d\n", ret);
10661109
}
10671110

1068-
/* Check for presence of a record, and update its timestamp */
1111+
/*
1112+
* For older nfsdcld's that do not allow us to "slurp" the clients
1113+
* from the tracking database during startup.
1114+
*
1115+
* Check for presence of a record, and update its timestamp
1116+
*/
10691117
static int
1070-
nfsd4_cld_check(struct nfs4_client *clp)
1118+
nfsd4_cld_check_v0(struct nfs4_client *clp)
10711119
{
10721120
int ret;
10731121
struct cld_upcall *cup;
@@ -1100,8 +1148,61 @@ nfsd4_cld_check(struct nfs4_client *clp)
11001148
return ret;
11011149
}
11021150

1151+
/*
1152+
* For newer nfsdcld's that allow us to "slurp" the clients
1153+
* from the tracking database during startup.
1154+
*
1155+
* Check for presence of a record in the reclaim_str_hashtbl
1156+
*/
1157+
static int
1158+
nfsd4_cld_check(struct nfs4_client *clp)
1159+
{
1160+
struct nfs4_client_reclaim *crp;
1161+
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1162+
1163+
/* did we already find that this client is stable? */
1164+
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1165+
return 0;
1166+
1167+
/* look for it in the reclaim hashtable otherwise */
1168+
crp = nfsd4_find_reclaim_client(clp->cl_name, nn);
1169+
if (crp) {
1170+
crp->cr_clp = clp;
1171+
return 0;
1172+
}
1173+
1174+
return -ENOENT;
1175+
}
1176+
1177+
static int
1178+
nfsd4_cld_grace_start(struct nfsd_net *nn)
1179+
{
1180+
int ret;
1181+
struct cld_upcall *cup;
1182+
struct cld_net *cn = nn->cld_net;
1183+
1184+
cup = alloc_cld_upcall(cn);
1185+
if (!cup) {
1186+
ret = -ENOMEM;
1187+
goto out_err;
1188+
}
1189+
1190+
cup->cu_msg.cm_cmd = Cld_GraceStart;
1191+
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
1192+
if (!ret)
1193+
ret = cup->cu_msg.cm_status;
1194+
1195+
free_cld_upcall(cup);
1196+
out_err:
1197+
if (ret)
1198+
dprintk("%s: Unable to get clients from userspace: %d\n",
1199+
__func__, ret);
1200+
return ret;
1201+
}
1202+
1203+
/* For older nfsdcld's that need cm_gracetime */
11031204
static void
1104-
nfsd4_cld_grace_done(struct nfsd_net *nn)
1205+
nfsd4_cld_grace_done_v0(struct nfsd_net *nn)
11051206
{
11061207
int ret;
11071208
struct cld_upcall *cup;
@@ -1125,11 +1226,118 @@ nfsd4_cld_grace_done(struct nfsd_net *nn)
11251226
printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
11261227
}
11271228

1128-
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1229+
/*
1230+
* For newer nfsdcld's that do not need cm_gracetime. We also need to call
1231+
* nfs4_release_reclaim() to clear out the reclaim_str_hashtbl.
1232+
*/
1233+
static void
1234+
nfsd4_cld_grace_done(struct nfsd_net *nn)
1235+
{
1236+
int ret;
1237+
struct cld_upcall *cup;
1238+
struct cld_net *cn = nn->cld_net;
1239+
1240+
cup = alloc_cld_upcall(cn);
1241+
if (!cup) {
1242+
ret = -ENOMEM;
1243+
goto out_err;
1244+
}
1245+
1246+
cup->cu_msg.cm_cmd = Cld_GraceDone;
1247+
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
1248+
if (!ret)
1249+
ret = cup->cu_msg.cm_status;
1250+
1251+
free_cld_upcall(cup);
1252+
out_err:
1253+
nfs4_release_reclaim(nn);
1254+
if (ret)
1255+
printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
1256+
}
1257+
1258+
static int
1259+
nfs4_cld_state_init(struct net *net)
1260+
{
1261+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1262+
int i;
1263+
1264+
nn->reclaim_str_hashtbl = kmalloc_array(CLIENT_HASH_SIZE,
1265+
sizeof(struct list_head),
1266+
GFP_KERNEL);
1267+
if (!nn->reclaim_str_hashtbl)
1268+
return -ENOMEM;
1269+
1270+
for (i = 0; i < CLIENT_HASH_SIZE; i++)
1271+
INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
1272+
nn->reclaim_str_hashtbl_size = 0;
1273+
1274+
return 0;
1275+
}
1276+
1277+
static void
1278+
nfs4_cld_state_shutdown(struct net *net)
1279+
{
1280+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1281+
1282+
kfree(nn->reclaim_str_hashtbl);
1283+
}
1284+
1285+
static int
1286+
nfsd4_cld_tracking_init(struct net *net)
1287+
{
1288+
int status;
1289+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1290+
1291+
status = nfs4_cld_state_init(net);
1292+
if (status)
1293+
return status;
1294+
1295+
status = nfsd4_init_cld_pipe(net);
1296+
if (status)
1297+
goto err_shutdown;
1298+
1299+
status = nfsd4_cld_grace_start(nn);
1300+
if (status) {
1301+
if (status == -EOPNOTSUPP)
1302+
printk(KERN_WARNING "NFSD: Please upgrade nfsdcld.\n");
1303+
nfs4_release_reclaim(nn);
1304+
goto err_remove;
1305+
}
1306+
return 0;
1307+
1308+
err_remove:
1309+
nfsd4_remove_cld_pipe(net);
1310+
err_shutdown:
1311+
nfs4_cld_state_shutdown(net);
1312+
return status;
1313+
}
1314+
1315+
static void
1316+
nfsd4_cld_tracking_exit(struct net *net)
1317+
{
1318+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1319+
1320+
nfs4_release_reclaim(nn);
1321+
nfsd4_remove_cld_pipe(net);
1322+
nfs4_cld_state_shutdown(net);
1323+
}
1324+
1325+
/* For older nfsdcld's */
1326+
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = {
11291327
.init = nfsd4_init_cld_pipe,
11301328
.exit = nfsd4_remove_cld_pipe,
11311329
.create = nfsd4_cld_create,
11321330
.remove = nfsd4_cld_remove,
1331+
.check = nfsd4_cld_check_v0,
1332+
.grace_done = nfsd4_cld_grace_done_v0,
1333+
};
1334+
1335+
/* For newer nfsdcld's */
1336+
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1337+
.init = nfsd4_cld_tracking_init,
1338+
.exit = nfsd4_cld_tracking_exit,
1339+
.create = nfsd4_cld_create,
1340+
.remove = nfsd4_cld_remove,
11331341
.check = nfsd4_cld_check,
11341342
.grace_done = nfsd4_cld_grace_done,
11351343
};
@@ -1514,9 +1722,10 @@ nfsd4_client_tracking_init(struct net *net)
15141722

15151723
/* Finally, try to use nfsdcld */
15161724
nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
1517-
printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be "
1518-
"removed in 3.10. Please transition to using "
1519-
"nfsdcltrack.\n");
1725+
status = nn->client_tracking_ops->init(net);
1726+
if (!status)
1727+
return status;
1728+
nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0;
15201729
do_init:
15211730
status = nn->client_tracking_ops->init(net);
15221731
if (status) {

include/uapi/linux/nfsd/cld.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum cld_command {
3636
Cld_Remove, /* remove record of this cm_id */
3737
Cld_Check, /* is this cm_id allowed? */
3838
Cld_GraceDone, /* grace period is complete */
39+
Cld_GraceStart,
3940
};
4041

4142
/* representation of long-form NFSv4 client ID */

0 commit comments

Comments
 (0)