1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* mountpoint management
3  *
4  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/fs.h>
12 #include <linux/pagemap.h>
13 #include <linux/mount.h>
14 #include <linux/namei.h>
15 #include <linux/gfp.h>
16 #include <linux/fs_context.h>
17 #include "internal.h"
18 
19 
20 static struct dentry *afs_mntpt_lookup(struct inode *dir,
21 				       struct dentry *dentry,
22 				       unsigned int flags);
23 static int afs_mntpt_open(struct inode *inode, struct file *file);
24 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
25 
26 const struct file_operations afs_mntpt_file_operations = {
27 	.open		= afs_mntpt_open,
28 	.llseek		= noop_llseek,
29 };
30 
31 const struct inode_operations afs_mntpt_inode_operations = {
32 	.lookup		= afs_mntpt_lookup,
33 	.readlink	= page_readlink,
34 	.getattr	= afs_getattr,
35 	.listxattr	= afs_listxattr,
36 };
37 
38 const struct inode_operations afs_autocell_inode_operations = {
39 	.getattr	= afs_getattr,
40 };
41 
42 static LIST_HEAD(afs_vfsmounts);
43 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
44 
45 static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
46 
47 static const char afs_root_volume[] = "root.cell";
48 
49 /*
50  * no valid lookup procedure on this sort of dir
51  */
afs_mntpt_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)52 static struct dentry *afs_mntpt_lookup(struct inode *dir,
53 				       struct dentry *dentry,
54 				       unsigned int flags)
55 {
56 	_enter("%p,%p{%pd2}", dir, dentry, dentry);
57 	return ERR_PTR(-EREMOTE);
58 }
59 
60 /*
61  * no valid open procedure on this sort of dir
62  */
afs_mntpt_open(struct inode * inode,struct file * file)63 static int afs_mntpt_open(struct inode *inode, struct file *file)
64 {
65 	_enter("%p,%p{%pD2}", inode, file, file);
66 	return -EREMOTE;
67 }
68 
69 /*
70  * Set the parameters for the proposed superblock.
71  */
afs_mntpt_set_params(struct fs_context * fc,struct dentry * mntpt)72 static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)
73 {
74 	struct afs_fs_context *ctx = fc->fs_private;
75 	struct afs_super_info *src_as = AFS_FS_S(mntpt->d_sb);
76 	struct afs_vnode *vnode = AFS_FS_I(d_inode(mntpt));
77 	struct afs_cell *cell;
78 	const char *p;
79 	int ret;
80 
81 	if (fc->net_ns != src_as->net_ns) {
82 		put_net(fc->net_ns);
83 		fc->net_ns = get_net(src_as->net_ns);
84 	}
85 
86 	if (src_as->volume && src_as->volume->type == AFSVL_RWVOL) {
87 		ctx->type = AFSVL_RWVOL;
88 		ctx->force = true;
89 	}
90 	if (ctx->cell) {
91 		afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_mntpt);
92 		ctx->cell = NULL;
93 	}
94 	if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
95 		/* if the directory is a pseudo directory, use the d_name */
96 		unsigned size = mntpt->d_name.len;
97 
98 		if (size < 2)
99 			return -ENOENT;
100 
101 		p = mntpt->d_name.name;
102 		if (mntpt->d_name.name[0] == '.') {
103 			size--;
104 			p++;
105 			ctx->type = AFSVL_RWVOL;
106 			ctx->force = true;
107 		}
108 		if (size > AFS_MAXCELLNAME)
109 			return -ENAMETOOLONG;
110 
111 		cell = afs_lookup_cell(ctx->net, p, size, NULL, false);
112 		if (IS_ERR(cell)) {
113 			pr_err("kAFS: unable to lookup cell '%pd'\n", mntpt);
114 			return PTR_ERR(cell);
115 		}
116 		ctx->cell = cell;
117 
118 		ctx->volname = afs_root_volume;
119 		ctx->volnamesz = sizeof(afs_root_volume) - 1;
120 	} else {
121 		/* read the contents of the AFS special symlink */
122 		struct page *page;
123 		loff_t size = i_size_read(d_inode(mntpt));
124 		char *buf;
125 
126 		if (src_as->cell)
127 			ctx->cell = afs_use_cell(src_as->cell, afs_cell_trace_use_mntpt);
128 
129 		if (size < 2 || size > PAGE_SIZE - 1)
130 			return -EINVAL;
131 
132 		page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);
133 		if (IS_ERR(page))
134 			return PTR_ERR(page);
135 
136 		if (PageError(page)) {
137 			ret = afs_bad(AFS_FS_I(d_inode(mntpt)), afs_file_error_mntpt);
138 			put_page(page);
139 			return ret;
140 		}
141 
142 		buf = kmap(page);
143 		ret = -EINVAL;
144 		if (buf[size - 1] == '.')
145 			ret = vfs_parse_fs_string(fc, "source", buf, size - 1);
146 		kunmap(page);
147 		put_page(page);
148 		if (ret < 0)
149 			return ret;
150 	}
151 
152 	return 0;
153 }
154 
155 /*
156  * create a vfsmount to be automounted
157  */
afs_mntpt_do_automount(struct dentry * mntpt)158 static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
159 {
160 	struct fs_context *fc;
161 	struct vfsmount *mnt;
162 	int ret;
163 
164 	BUG_ON(!d_inode(mntpt));
165 
166 	fc = fs_context_for_submount(&afs_fs_type, mntpt);
167 	if (IS_ERR(fc))
168 		return ERR_CAST(fc);
169 
170 	ret = afs_mntpt_set_params(fc, mntpt);
171 	if (!ret)
172 		mnt = fc_mount(fc);
173 	else
174 		mnt = ERR_PTR(ret);
175 
176 	put_fs_context(fc);
177 	return mnt;
178 }
179 
180 /*
181  * handle an automount point
182  */
afs_d_automount(struct path * path)183 struct vfsmount *afs_d_automount(struct path *path)
184 {
185 	struct vfsmount *newmnt;
186 
187 	_enter("{%pd}", path->dentry);
188 
189 	newmnt = afs_mntpt_do_automount(path->dentry);
190 	if (IS_ERR(newmnt))
191 		return newmnt;
192 
193 	mntget(newmnt); /* prevent immediate expiration */
194 	mnt_set_expiry(newmnt, &afs_vfsmounts);
195 	queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
196 			   afs_mntpt_expiry_timeout * HZ);
197 	_leave(" = %p", newmnt);
198 	return newmnt;
199 }
200 
201 /*
202  * handle mountpoint expiry timer going off
203  */
afs_mntpt_expiry_timed_out(struct work_struct * work)204 static void afs_mntpt_expiry_timed_out(struct work_struct *work)
205 {
206 	_enter("");
207 
208 	if (!list_empty(&afs_vfsmounts)) {
209 		mark_mounts_for_expiry(&afs_vfsmounts);
210 		queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
211 				   afs_mntpt_expiry_timeout * HZ);
212 	}
213 
214 	_leave("");
215 }
216 
217 /*
218  * kill the AFS mountpoint timer if it's still running
219  */
afs_mntpt_kill_timer(void)220 void afs_mntpt_kill_timer(void)
221 {
222 	_enter("");
223 
224 	ASSERT(list_empty(&afs_vfsmounts));
225 	cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
226 }
227