brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 297487e Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* mountpoint management3 *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 20static struct dentry *afs_mntpt_lookup(struct inode *dir,21				       struct dentry *dentry,22				       unsigned int flags);23static int afs_mntpt_open(struct inode *inode, struct file *file);24static void afs_mntpt_expiry_timed_out(struct work_struct *work);25 26const struct file_operations afs_mntpt_file_operations = {27	.open		= afs_mntpt_open,28	.llseek		= noop_llseek,29};30 31const struct inode_operations afs_mntpt_inode_operations = {32	.lookup		= afs_mntpt_lookup,33	.readlink	= page_readlink,34	.getattr	= afs_getattr,35};36 37const struct inode_operations afs_autocell_inode_operations = {38	.getattr	= afs_getattr,39};40 41static LIST_HEAD(afs_vfsmounts);42static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);43 44static unsigned long afs_mntpt_expiry_timeout = 10 * 60;45 46static const char afs_root_volume[] = "root.cell";47 48/*49 * no valid lookup procedure on this sort of dir50 */51static struct dentry *afs_mntpt_lookup(struct inode *dir,52				       struct dentry *dentry,53				       unsigned int flags)54{55	_enter("%p,%p{%pd2}", dir, dentry, dentry);56	return ERR_PTR(-EREMOTE);57}58 59/*60 * no valid open procedure on this sort of dir61 */62static int afs_mntpt_open(struct inode *inode, struct file *file)63{64	_enter("%p,%p{%pD2}", inode, file, file);65	return -EREMOTE;66}67 68/*69 * Set the parameters for the proposed superblock.70 */71static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)72{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;78	int ret;79 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	}84 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) {90		afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_mntpt);91		ctx->cell = NULL;92	}93	if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {94		/* if the directory is a pseudo directory, use the d_name */95		unsigned size = mntpt->d_name.len;96 97		if (size < 2)98			return -ENOENT;99 100		p = mntpt->d_name.name;101		if (mntpt->d_name.name[0] == '.') {102			size--;103			p++;104			ctx->type = AFSVL_RWVOL;105			ctx->force = true;106		}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;119	} else {120		/* read the contents of the AFS special symlink */121		struct page *page;122		loff_t size = i_size_read(d_inode(mntpt));123		char *buf;124 125		if (src_as->cell)126			ctx->cell = afs_use_cell(src_as->cell, afs_cell_trace_use_mntpt);127 128		if (size < 2 || size > PAGE_SIZE - 1)129			return -EINVAL;130 131		page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);132		if (IS_ERR(page))133			return PTR_ERR(page);134 135		buf = kmap(page);136		ret = -EINVAL;137		if (buf[size - 1] == '.')138			ret = vfs_parse_fs_string(fc, "source", buf, size - 1);139		kunmap(page);140		put_page(page);141		if (ret < 0)142			return ret;143 144		/* Don't cross a backup volume mountpoint from a backup volume */145		if (src_as->volume && src_as->volume->type == AFSVL_BACKVOL &&146		    ctx->type == AFSVL_BACKVOL)147			return -ENODEV;148	}149 150	return 0;151}152 153/*154 * create a vfsmount to be automounted155 */156static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)157{158	struct fs_context *fc;159	struct vfsmount *mnt;160	int ret;161 162	BUG_ON(!d_inode(mntpt));163 164	fc = fs_context_for_submount(&afs_fs_type, mntpt);165	if (IS_ERR(fc))166		return ERR_CAST(fc);167 168	ret = afs_mntpt_set_params(fc, mntpt);169	if (!ret)170		mnt = fc_mount(fc);171	else172		mnt = ERR_PTR(ret);173 174	put_fs_context(fc);175	return mnt;176}177 178/*179 * handle an automount point180 */181struct vfsmount *afs_d_automount(struct path *path)182{183	struct vfsmount *newmnt;184 185	_enter("{%pd}", path->dentry);186 187	newmnt = afs_mntpt_do_automount(path->dentry);188	if (IS_ERR(newmnt))189		return newmnt;190 191	mntget(newmnt); /* prevent immediate expiration */192	mnt_set_expiry(newmnt, &afs_vfsmounts);193	queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,194			   afs_mntpt_expiry_timeout * HZ);195	_leave(" = %p", newmnt);196	return newmnt;197}198 199/*200 * handle mountpoint expiry timer going off201 */202static void afs_mntpt_expiry_timed_out(struct work_struct *work)203{204	_enter("");205 206	if (!list_empty(&afs_vfsmounts)) {207		mark_mounts_for_expiry(&afs_vfsmounts);208		queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,209				   afs_mntpt_expiry_timeout * HZ);210	}211 212	_leave("");213}214 215/*216 * kill the AFS mountpoint timer if it's still running217 */218void afs_mntpt_kill_timer(void)219{220	_enter("");221 222	ASSERT(list_empty(&afs_vfsmounts));223	cancel_delayed_work_sync(&afs_mntpt_expiry_timer);224}225