@@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644);
5555MODULE_PARM_DESC (inter_copy_offload_enable ,
5656 "Enable inter server to server copy offload. Default: false" );
5757
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+
5865#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
5966#include <linux/security.h>
6067
@@ -1165,6 +1172,81 @@ extern void nfs_sb_deactive(struct super_block *sb);
11651172
11661173#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
11671174
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+
11681250/*
11691251 * Support one copy source server for now.
11701252 */
@@ -1181,6 +1263,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
11811263 char * ipaddr , * dev_name , * raw_data ;
11821264 int len , raw_len ;
11831265 __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 );
11841268
11851269 naddr = & nss -> u .nl4_addr ;
11861270 tmp_addrlen = rpc_uaddr2sockaddr (SVC_NET (rqstp ), naddr -> addr ,
@@ -1229,12 +1313,23 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
12291313 goto out_free_rawdata ;
12301314 snprintf (dev_name , len + 5 , "%s%s%s:/" , startsep , ipaddr , endsep );
12311315
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+
12321322 /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
12331323 ss_mnt = vfs_kern_mount (type , SB_KERNMOUNT , dev_name , raw_data );
12341324 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 );
12361328 goto out_free_devname ;
1237-
1329+ }
1330+ if (work )
1331+ nfsd4_ssc_update_dul_work (nn , work , ss_mnt );
1332+ out_done :
12381333 status = 0 ;
12391334 * mount = ss_mnt ;
12401335
@@ -1301,10 +1396,42 @@ static void
13011396nfsd4_cleanup_inter_ssc (struct vfsmount * ss_mnt , struct nfsd_file * src ,
13021397 struct nfsd_file * dst )
13031398{
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+
13041405 nfs42_ssc_close (src -> nf_file );
1305- fput (src -> nf_file );
13061406 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+ }
13081435}
13091436
13101437#else /* CONFIG_NFSD_V4_2_INTER_SSC */
0 commit comments