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