@@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644);
55
55
MODULE_PARM_DESC (inter_copy_offload_enable ,
56
56
"Enable inter server to server copy offload. Default: false" );
57
57
58
+ #ifdef CONFIG_NFSD_V4_2_INTER_SSC
59
+ static int nfsd4_ssc_umount_timeout = 900000 ; /* default to 15 mins */
60
+ module_param (nfsd4_ssc_umount_timeout , int , 0644 );
61
+ MODULE_PARM_DESC (nfsd4_ssc_umount_timeout ,
62
+ "idle msecs before unmount export from source server" );
63
+ #endif
64
+
58
65
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
59
66
#include <linux/security.h>
60
67
@@ -1165,6 +1172,81 @@ extern void nfs_sb_deactive(struct super_block *sb);
1165
1172
1166
1173
#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
1167
1174
1175
+ /*
1176
+ * setup a work entry in the ssc delayed unmount list.
1177
+ */
1178
+ static int nfsd4_ssc_setup_dul (struct nfsd_net * nn , char * ipaddr ,
1179
+ struct nfsd4_ssc_umount_item * * retwork , struct vfsmount * * ss_mnt )
1180
+ {
1181
+ struct nfsd4_ssc_umount_item * ni = 0 ;
1182
+ struct nfsd4_ssc_umount_item * work = NULL ;
1183
+ struct nfsd4_ssc_umount_item * tmp ;
1184
+ DEFINE_WAIT (wait );
1185
+
1186
+ * ss_mnt = NULL ;
1187
+ * retwork = NULL ;
1188
+ work = kzalloc (sizeof (* work ), GFP_KERNEL );
1189
+ try_again :
1190
+ spin_lock (& nn -> nfsd_ssc_lock );
1191
+ list_for_each_entry_safe (ni , tmp , & nn -> nfsd_ssc_mount_list , nsui_list ) {
1192
+ if (strncmp (ni -> nsui_ipaddr , ipaddr , sizeof (ni -> nsui_ipaddr )))
1193
+ continue ;
1194
+ /* found a match */
1195
+ if (ni -> nsui_busy ) {
1196
+ /* wait - and try again */
1197
+ prepare_to_wait (& nn -> nfsd_ssc_waitq , & wait ,
1198
+ TASK_INTERRUPTIBLE );
1199
+ spin_unlock (& nn -> nfsd_ssc_lock );
1200
+
1201
+ /* allow 20secs for mount/unmount for now - revisit */
1202
+ if (signal_pending (current ) ||
1203
+ (schedule_timeout (20 * HZ ) == 0 )) {
1204
+ kfree (work );
1205
+ return nfserr_eagain ;
1206
+ }
1207
+ finish_wait (& nn -> nfsd_ssc_waitq , & wait );
1208
+ goto try_again ;
1209
+ }
1210
+ * ss_mnt = ni -> nsui_vfsmount ;
1211
+ refcount_inc (& ni -> nsui_refcnt );
1212
+ spin_unlock (& nn -> nfsd_ssc_lock );
1213
+ kfree (work );
1214
+
1215
+ /* return vfsmount in ss_mnt */
1216
+ return 0 ;
1217
+ }
1218
+ if (work ) {
1219
+ strncpy (work -> nsui_ipaddr , ipaddr , sizeof (work -> nsui_ipaddr ));
1220
+ refcount_set (& work -> nsui_refcnt , 2 );
1221
+ work -> nsui_busy = true;
1222
+ list_add_tail (& work -> nsui_list , & nn -> nfsd_ssc_mount_list );
1223
+ * retwork = work ;
1224
+ }
1225
+ spin_unlock (& nn -> nfsd_ssc_lock );
1226
+ return 0 ;
1227
+ }
1228
+
1229
+ static void nfsd4_ssc_update_dul_work (struct nfsd_net * nn ,
1230
+ struct nfsd4_ssc_umount_item * work , struct vfsmount * ss_mnt )
1231
+ {
1232
+ /* set nsui_vfsmount, clear busy flag and wakeup waiters */
1233
+ spin_lock (& nn -> nfsd_ssc_lock );
1234
+ work -> nsui_vfsmount = ss_mnt ;
1235
+ work -> nsui_busy = false;
1236
+ wake_up_all (& nn -> nfsd_ssc_waitq );
1237
+ spin_unlock (& nn -> nfsd_ssc_lock );
1238
+ }
1239
+
1240
+ static void nfsd4_ssc_cancel_dul_work (struct nfsd_net * nn ,
1241
+ struct nfsd4_ssc_umount_item * work )
1242
+ {
1243
+ spin_lock (& nn -> nfsd_ssc_lock );
1244
+ list_del (& work -> nsui_list );
1245
+ wake_up_all (& nn -> nfsd_ssc_waitq );
1246
+ spin_unlock (& nn -> nfsd_ssc_lock );
1247
+ kfree (work );
1248
+ }
1249
+
1168
1250
/*
1169
1251
* Support one copy source server for now.
1170
1252
*/
@@ -1181,6 +1263,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
1181
1263
char * ipaddr , * dev_name , * raw_data ;
1182
1264
int len , raw_len ;
1183
1265
__be32 status = nfserr_inval ;
1266
+ struct nfsd4_ssc_umount_item * work = NULL ;
1267
+ struct nfsd_net * nn = net_generic (SVC_NET (rqstp ), nfsd_net_id );
1184
1268
1185
1269
naddr = & nss -> u .nl4_addr ;
1186
1270
tmp_addrlen = rpc_uaddr2sockaddr (SVC_NET (rqstp ), naddr -> addr ,
@@ -1229,12 +1313,23 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
1229
1313
goto out_free_rawdata ;
1230
1314
snprintf (dev_name , len + 5 , "%s%s%s:/" , startsep , ipaddr , endsep );
1231
1315
1316
+ status = nfsd4_ssc_setup_dul (nn , ipaddr , & work , & ss_mnt );
1317
+ if (status )
1318
+ goto out_free_devname ;
1319
+ if (ss_mnt )
1320
+ goto out_done ;
1321
+
1232
1322
/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
1233
1323
ss_mnt = vfs_kern_mount (type , SB_KERNMOUNT , dev_name , raw_data );
1234
1324
module_put (type -> owner );
1235
- if (IS_ERR (ss_mnt ))
1325
+ if (IS_ERR (ss_mnt )) {
1326
+ if (work )
1327
+ nfsd4_ssc_cancel_dul_work (nn , work );
1236
1328
goto out_free_devname ;
1237
-
1329
+ }
1330
+ if (work )
1331
+ nfsd4_ssc_update_dul_work (nn , work , ss_mnt );
1332
+ out_done :
1238
1333
status = 0 ;
1239
1334
* mount = ss_mnt ;
1240
1335
@@ -1301,10 +1396,42 @@ static void
1301
1396
nfsd4_cleanup_inter_ssc (struct vfsmount * ss_mnt , struct nfsd_file * src ,
1302
1397
struct nfsd_file * dst )
1303
1398
{
1399
+ bool found = false;
1400
+ long timeout ;
1401
+ struct nfsd4_ssc_umount_item * tmp ;
1402
+ struct nfsd4_ssc_umount_item * ni = 0 ;
1403
+ struct nfsd_net * nn = net_generic (dst -> nf_net , nfsd_net_id );
1404
+
1304
1405
nfs42_ssc_close (src -> nf_file );
1305
- fput (src -> nf_file );
1306
1406
nfsd_file_put (dst );
1307
- mntput (ss_mnt );
1407
+ fput (src -> nf_file );
1408
+
1409
+ if (!nn ) {
1410
+ mntput (ss_mnt );
1411
+ return ;
1412
+ }
1413
+ spin_lock (& nn -> nfsd_ssc_lock );
1414
+ timeout = msecs_to_jiffies (nfsd4_ssc_umount_timeout );
1415
+ list_for_each_entry_safe (ni , tmp , & nn -> nfsd_ssc_mount_list , nsui_list ) {
1416
+ if (ni -> nsui_vfsmount -> mnt_sb == ss_mnt -> mnt_sb ) {
1417
+ list_del (& ni -> nsui_list );
1418
+ /*
1419
+ * vfsmount can be shared by multiple exports,
1420
+ * decrement refcnt. If the count drops to 1 it
1421
+ * will be unmounted when nsui_expire expires.
1422
+ */
1423
+ refcount_dec (& ni -> nsui_refcnt );
1424
+ ni -> nsui_expire = jiffies + timeout ;
1425
+ list_add_tail (& ni -> nsui_list , & nn -> nfsd_ssc_mount_list );
1426
+ found = true;
1427
+ break ;
1428
+ }
1429
+ }
1430
+ spin_unlock (& nn -> nfsd_ssc_lock );
1431
+ if (!found ) {
1432
+ mntput (ss_mnt );
1433
+ return ;
1434
+ }
1308
1435
}
1309
1436
1310
1437
#else /* CONFIG_NFSD_V4_2_INTER_SSC */
0 commit comments