diff options
Diffstat (limited to 'fs/nfs/namespace.c')
| -rw-r--r-- | fs/nfs/namespace.c | 67 | 
1 files changed, 58 insertions, 9 deletions
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index f3ece8ed3203..6b063227e34e 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -145,6 +145,7 @@ struct vfsmount *nfs_d_automount(struct path *path)  	struct vfsmount *mnt = ERR_PTR(-ENOMEM);  	struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));  	struct nfs_client *client = server->nfs_client; +	int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);  	int ret;  	if (IS_ROOT(path->dentry)) @@ -190,12 +191,12 @@ struct vfsmount *nfs_d_automount(struct path *path)  	if (IS_ERR(mnt))  		goto out_fc; -	if (nfs_mountpoint_expiry_timeout < 0) +	mntget(mnt); /* prevent immediate expiration */ +	if (timeout <= 0)  		goto out_fc; -	mntget(mnt); /* prevent immediate expiration */  	mnt_set_expiry(mnt, &nfs_automount_list); -	schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); +	schedule_delayed_work(&nfs_automount_task, timeout);  out_fc:  	put_fs_context(fc); @@ -233,10 +234,11 @@ const struct inode_operations nfs_referral_inode_operations = {  static void nfs_expire_automounts(struct work_struct *work)  {  	struct list_head *list = &nfs_automount_list; +	int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);  	mark_mounts_for_expiry(list); -	if (!list_empty(list)) -		schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); +	if (!list_empty(list) && timeout > 0) +		schedule_delayed_work(&nfs_automount_task, timeout);  }  void nfs_release_automount_timer(void) @@ -247,10 +249,7 @@ void nfs_release_automount_timer(void)  /**   * nfs_do_submount - set up mountpoint when crossing a filesystem boundary - * @dentry: parent directory - * @fh: filehandle for new root dentry - * @fattr: attributes for new root inode - * @authflavor: security flavor to use when performing the mount + * @fc: pointer to struct nfs_fs_context   *   */  int nfs_do_submount(struct fs_context *fc) @@ -312,3 +311,53 @@ int nfs_submount(struct fs_context *fc, struct nfs_server *server)  	return nfs_do_submount(fc);  }  EXPORT_SYMBOL_GPL(nfs_submount); + +static int param_set_nfs_timeout(const char *val, const struct kernel_param *kp) +{ +	long num; +	int ret; + +	if (!val) +		return -EINVAL; +	ret = kstrtol(val, 0, &num); +	if (ret) +		return -EINVAL; +	if (num > 0) { +		if (num >= INT_MAX / HZ) +			num = INT_MAX; +		else +			num *= HZ; +		*((int *)kp->arg) = num; +		if (!list_empty(&nfs_automount_list)) +			mod_delayed_work(system_wq, &nfs_automount_task, num); +	} else { +		*((int *)kp->arg) = -1*HZ; +		cancel_delayed_work(&nfs_automount_task); +	} +	return 0; +} + +static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp) +{ +	long num = *((int *)kp->arg); + +	if (num > 0) { +		if (num >= INT_MAX - (HZ - 1)) +			num = INT_MAX / HZ; +		else +			num = (num + (HZ - 1)) / HZ; +	} else +		num = -1; +	return scnprintf(buffer, PAGE_SIZE, "%li\n", num); +} + +static const struct kernel_param_ops param_ops_nfs_timeout = { +	.set = param_set_nfs_timeout, +	.get = param_get_nfs_timeout, +}; +#define param_check_nfs_timeout(name, p) __param_check(name, p, int); + +module_param(nfs_mountpoint_expiry_timeout, nfs_timeout, 0644); +MODULE_PARM_DESC(nfs_mountpoint_expiry_timeout, +		"Set the NFS automounted mountpoint timeout value (seconds)." +		"Values <= 0 turn expiration off.");  |