@@ -779,6 +779,34 @@ cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
779
779
return ret ;
780
780
}
781
781
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
+
782
810
static ssize_t
783
811
cld_pipe_downcall (struct file * filp , const char __user * src , size_t mlen )
784
812
{
@@ -788,6 +816,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
788
816
struct nfsd_net * nn = net_generic (file_inode (filp )-> i_sb -> s_fs_info ,
789
817
nfsd_net_id );
790
818
struct cld_net * cn = nn -> cld_net ;
819
+ int16_t status ;
791
820
792
821
if (mlen != sizeof (* cmsg )) {
793
822
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)
801
830
return - EFAULT ;
802
831
}
803
832
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
+
804
843
/* walk the list and find corresponding xid */
805
844
cup = NULL ;
806
845
spin_lock (& cn -> cn_lock );
807
846
list_for_each_entry (tmp , & cn -> cn_list , cu_list ) {
808
847
if (get_unaligned (& tmp -> cu_msg .cm_xid ) == xid ) {
809
848
cup = tmp ;
810
- list_del_init (& cup -> cu_list );
849
+ if (status != - EINPROGRESS )
850
+ list_del_init (& cup -> cu_list );
811
851
break ;
812
852
}
813
853
}
@@ -819,6 +859,9 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
819
859
return - EINVAL ;
820
860
}
821
861
862
+ if (status == - EINPROGRESS )
863
+ return __cld_pipe_inprogress_downcall (cmsg , nn );
864
+
822
865
if (copy_from_user (& cup -> cu_msg , src , mlen ) != 0 )
823
866
return - EFAULT ;
824
867
@@ -1065,9 +1108,14 @@ nfsd4_cld_remove(struct nfs4_client *clp)
1065
1108
"record from stable storage: %d\n" , ret );
1066
1109
}
1067
1110
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
+ */
1069
1117
static int
1070
- nfsd4_cld_check (struct nfs4_client * clp )
1118
+ nfsd4_cld_check_v0 (struct nfs4_client * clp )
1071
1119
{
1072
1120
int ret ;
1073
1121
struct cld_upcall * cup ;
@@ -1100,8 +1148,61 @@ nfsd4_cld_check(struct nfs4_client *clp)
1100
1148
return ret ;
1101
1149
}
1102
1150
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 */
1103
1204
static void
1104
- nfsd4_cld_grace_done (struct nfsd_net * nn )
1205
+ nfsd4_cld_grace_done_v0 (struct nfsd_net * nn )
1105
1206
{
1106
1207
int ret ;
1107
1208
struct cld_upcall * cup ;
@@ -1125,11 +1226,118 @@ nfsd4_cld_grace_done(struct nfsd_net *nn)
1125
1226
printk (KERN_ERR "NFSD: Unable to end grace period: %d\n" , ret );
1126
1227
}
1127
1228
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 = {
1129
1327
.init = nfsd4_init_cld_pipe ,
1130
1328
.exit = nfsd4_remove_cld_pipe ,
1131
1329
.create = nfsd4_cld_create ,
1132
1330
.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 ,
1133
1341
.check = nfsd4_cld_check ,
1134
1342
.grace_done = nfsd4_cld_grace_done ,
1135
1343
};
@@ -1514,9 +1722,10 @@ nfsd4_client_tracking_init(struct net *net)
1514
1722
1515
1723
/* Finally, try to use nfsdcld */
1516
1724
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 ;
1520
1729
do_init :
1521
1730
status = nn -> client_tracking_ops -> init (net );
1522
1731
if (status ) {
0 commit comments