inode.c 8.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/* -*- c -*- --------------------------------------------------------------- *
 *
 * linux/fs/autofs/inode.c
 *
 *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
6
 *  Copyright 2005-2006 Ian Kent <raven@themaw.net>
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16
 *
 * This file is part of the Linux kernel and is made available under
 * the terms of the GNU General Public License, version 2, or at your
 * option, any later version, incorporated herein by reference.
 *
 * ------------------------------------------------------------------------- */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/file.h>
17
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
18 19 20
#include <linux/pagemap.h>
#include <linux/parser.h>
#include <linux/bitops.h>
21
#include <linux/magic.h>
L
Linus Torvalds 已提交
22 23 24
#include "autofs_i.h"
#include <linux/module.h>

A
Al Viro 已提交
25
struct autofs_info *autofs4_new_ino(struct autofs_sb_info *sbi)
L
Linus Torvalds 已提交
26
{
A
Al Viro 已提交
27 28
	struct autofs_info *ino = kzalloc(sizeof(*ino), GFP_KERNEL);
	if (ino) {
29 30
		INIT_LIST_HEAD(&ino->active);
		INIT_LIST_HEAD(&ino->expiring);
A
Al Viro 已提交
31 32
		ino->last_used = jiffies;
		ino->sbi = sbi;
33
	}
A
Al Viro 已提交
34 35
	return ino;
}
36

A
Al Viro 已提交
37 38
void autofs4_clean_ino(struct autofs_info *ino)
{
39 40
	ino->uid = 0;
	ino->gid = 0;
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48
	ino->last_used = jiffies;
}

void autofs4_free_ino(struct autofs_info *ino)
{
	kfree(ino);
}

49
void autofs4_kill_sb(struct super_block *sb)
L
Linus Torvalds 已提交
50 51 52
{
	struct autofs_sb_info *sbi = autofs4_sbi(sb);

I
Ian Kent 已提交
53 54 55
	/*
	 * In the event of a failure in get_sb_nodev the superblock
	 * info is not present so nothing else has been setup, so
56 57
	 * just call kill_anon_super when we are called from
	 * deactivate_super.
I
Ian Kent 已提交
58 59
	 */
	if (!sbi)
60
		goto out_kill_sb;
I
Ian Kent 已提交
61

I
Ian Kent 已提交
62 63
	/* Free wait queues, close pipe */
	autofs4_catatonic_mode(sbi);
L
Linus Torvalds 已提交
64

65
	sb->s_fs_info = NULL;
L
Linus Torvalds 已提交
66 67
	kfree(sbi);

68
out_kill_sb:
L
Linus Torvalds 已提交
69
	DPRINTK("shutting down");
70
	kill_litter_super(sb);
L
Linus Torvalds 已提交
71 72
}

73
static int autofs4_show_options(struct seq_file *m, struct dentry *root)
74
{
75 76
	struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
	struct inode *root_inode = root->d_sb->s_root->d_inode;
77 78 79 80 81

	if (!sbi)
		return 0;

	seq_printf(m, ",fd=%d", sbi->pipefd);
M
Miklos Szeredi 已提交
82 83 84 85
	if (root_inode->i_uid != 0)
		seq_printf(m, ",uid=%u", root_inode->i_uid);
	if (root_inode->i_gid != 0)
		seq_printf(m, ",gid=%u", root_inode->i_gid);
86 87 88 89 90
	seq_printf(m, ",pgrp=%d", sbi->oz_pgrp);
	seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ);
	seq_printf(m, ",minproto=%d", sbi->min_proto);
	seq_printf(m, ",maxproto=%d", sbi->max_proto);

91
	if (autofs_type_offset(sbi->type))
92
		seq_printf(m, ",offset");
93
	else if (autofs_type_direct(sbi->type))
94 95 96 97
		seq_printf(m, ",direct");
	else
		seq_printf(m, ",indirect");

98 99 100
	return 0;
}

101 102
static void autofs4_evict_inode(struct inode *inode)
{
103
	clear_inode(inode);
104 105 106
	kfree(inode->i_private);
}

107
static const struct super_operations autofs4_sops = {
L
Linus Torvalds 已提交
108
	.statfs		= simple_statfs,
109
	.show_options	= autofs4_show_options,
110
	.evict_inode	= autofs4_evict_inode,
L
Linus Torvalds 已提交
111 112
};

113 114
enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
	Opt_indirect, Opt_direct, Opt_offset};
L
Linus Torvalds 已提交
115

116
static const match_table_t tokens = {
L
Linus Torvalds 已提交
117 118 119 120 121 122
	{Opt_fd, "fd=%u"},
	{Opt_uid, "uid=%u"},
	{Opt_gid, "gid=%u"},
	{Opt_pgrp, "pgrp=%u"},
	{Opt_minproto, "minproto=%u"},
	{Opt_maxproto, "maxproto=%u"},
123 124 125
	{Opt_indirect, "indirect"},
	{Opt_direct, "direct"},
	{Opt_offset, "offset"},
L
Linus Torvalds 已提交
126 127 128 129
	{Opt_err, NULL}
};

static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
130
		pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto)
L
Linus Torvalds 已提交
131 132 133 134 135
{
	char *p;
	substring_t args[MAX_OPT_ARGS];
	int option;

136 137
	*uid = current_uid();
	*gid = current_gid();
P
Pavel Emelianov 已提交
138
	*pgrp = task_pgrp_nr(current);
L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

	*minproto = AUTOFS_MIN_PROTO_VERSION;
	*maxproto = AUTOFS_MAX_PROTO_VERSION;

	*pipefd = -1;

	if (!options)
		return 1;

	while ((p = strsep(&options, ",")) != NULL) {
		int token;
		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_fd:
			if (match_int(args, pipefd))
				return 1;
			break;
		case Opt_uid:
			if (match_int(args, &option))
				return 1;
			*uid = option;
			break;
		case Opt_gid:
			if (match_int(args, &option))
				return 1;
			*gid = option;
			break;
		case Opt_pgrp:
			if (match_int(args, &option))
				return 1;
			*pgrp = option;
			break;
		case Opt_minproto:
			if (match_int(args, &option))
				return 1;
			*minproto = option;
			break;
		case Opt_maxproto:
			if (match_int(args, &option))
				return 1;
			*maxproto = option;
			break;
184
		case Opt_indirect:
185
			set_autofs_type_indirect(type);
186 187
			break;
		case Opt_direct:
188
			set_autofs_type_direct(type);
189 190
			break;
		case Opt_offset:
191
			set_autofs_type_offset(type);
192
			break;
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
		default:
			return 1;
		}
	}
	return (*pipefd < 0);
}

int autofs4_fill_super(struct super_block *s, void *data, int silent)
{
	struct inode * root_inode;
	struct dentry * root;
	struct file * pipe;
	int pipefd;
	struct autofs_sb_info *sbi;
	struct autofs_info *ino;

209
	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
210
	if (!sbi)
L
Linus Torvalds 已提交
211 212 213 214 215
		goto fail_unlock;
	DPRINTK("starting up, sbi = %p",sbi);

	s->s_fs_info = sbi;
	sbi->magic = AUTOFS_SBI_MAGIC;
216
	sbi->pipefd = -1;
I
Ian Kent 已提交
217 218
	sbi->pipe = NULL;
	sbi->catatonic = 1;
L
Linus Torvalds 已提交
219
	sbi->exp_timeout = 0;
P
Pavel Emelianov 已提交
220
	sbi->oz_pgrp = task_pgrp_nr(current);
L
Linus Torvalds 已提交
221 222 223
	sbi->sb = s;
	sbi->version = 0;
	sbi->sub_version = 0;
224
	set_autofs_type_indirect(&sbi->type);
225 226
	sbi->min_proto = 0;
	sbi->max_proto = 0;
I
Ingo Molnar 已提交
227
	mutex_init(&sbi->wq_mutex);
228
	mutex_init(&sbi->pipe_mutex);
I
Ian Kent 已提交
229
	spin_lock_init(&sbi->fs_lock);
L
Linus Torvalds 已提交
230
	sbi->queues = NULL;
231
	spin_lock_init(&sbi->lookup_lock);
232
	INIT_LIST_HEAD(&sbi->active_list);
233
	INIT_LIST_HEAD(&sbi->expiring_list);
L
Linus Torvalds 已提交
234 235 236 237
	s->s_blocksize = 1024;
	s->s_blocksize_bits = 10;
	s->s_magic = AUTOFS_SUPER_MAGIC;
	s->s_op = &autofs4_sops;
238
	s->s_d_op = &autofs4_dentry_operations;
L
Linus Torvalds 已提交
239 240 241 242 243
	s->s_time_gran = 1;

	/*
	 * Get the root inode and dentry, but defer checking for errors.
	 */
A
Al Viro 已提交
244
	ino = autofs4_new_ino(sbi);
L
Linus Torvalds 已提交
245 246
	if (!ino)
		goto fail_free;
247
	root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
248
	root = d_make_root(root_inode);
L
Linus Torvalds 已提交
249
	if (!root)
250
		goto fail_ino;
251 252 253
	pipe = NULL;

	root->d_fsdata = ino;
L
Linus Torvalds 已提交
254 255

	/* Can this call block? */
256 257 258
	if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid,
				&sbi->oz_pgrp, &sbi->type, &sbi->min_proto,
				&sbi->max_proto)) {
L
Linus Torvalds 已提交
259 260 261 262
		printk("autofs: called with bogus options\n");
		goto fail_dput;
	}

263
	if (autofs_type_trigger(sbi->type))
264
		__managed_dentry_set_managed(root);
265

266
	root_inode->i_fop = &autofs4_root_operations;
I
Ian Kent 已提交
267
	root_inode->i_op = &autofs4_dir_inode_operations;
268

L
Linus Torvalds 已提交
269
	/* Couldn't this be tested earlier? */
270 271
	if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION ||
	    sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) {
L
Linus Torvalds 已提交
272 273
		printk("autofs: kernel does not match daemon version "
		       "daemon (%d, %d) kernel (%d, %d)\n",
274
			sbi->min_proto, sbi->max_proto,
L
Linus Torvalds 已提交
275 276 277 278
			AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION);
		goto fail_dput;
	}

279 280 281 282 283
	/* Establish highest kernel protocol version */
	if (sbi->max_proto > AUTOFS_MAX_PROTO_VERSION)
		sbi->version = AUTOFS_MAX_PROTO_VERSION;
	else
		sbi->version = sbi->max_proto;
L
Linus Torvalds 已提交
284 285 286 287 288
	sbi->sub_version = AUTOFS_PROTO_SUBVERSION;

	DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
	pipe = fget(pipefd);
	
289
	if (!pipe) {
L
Linus Torvalds 已提交
290 291 292
		printk("autofs: could not open pipe file descriptor\n");
		goto fail_dput;
	}
293
	if (autofs_prepare_pipe(pipe) < 0)
L
Linus Torvalds 已提交
294 295
		goto fail_fput;
	sbi->pipe = pipe;
296
	sbi->pipefd = pipefd;
I
Ian Kent 已提交
297
	sbi->catatonic = 0;
L
Linus Torvalds 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

	/*
	 * Success! Install the root dentry now to indicate completion.
	 */
	s->s_root = root;
	return 0;
	
	/*
	 * Failure ... clean up.
	 */
fail_fput:
	printk("autofs: pipe file descriptor does not contain proper ops\n");
	fput(pipe);
	/* fall through */
fail_dput:
	dput(root);
	goto fail_free;
315 316
fail_ino:
	kfree(ino);
L
Linus Torvalds 已提交
317 318
fail_free:
	kfree(sbi);
I
Ian Kent 已提交
319
	s->s_fs_info = NULL;
L
Linus Torvalds 已提交
320 321 322 323
fail_unlock:
	return -EINVAL;
}

A
Al Viro 已提交
324
struct inode *autofs4_get_inode(struct super_block *sb, umode_t mode)
L
Linus Torvalds 已提交
325 326 327 328 329 330
{
	struct inode *inode = new_inode(sb);

	if (inode == NULL)
		return NULL;

331
	inode->i_mode = mode;
L
Linus Torvalds 已提交
332 333 334 335 336
	if (sb->s_root) {
		inode->i_uid = sb->s_root->d_inode->i_uid;
		inode->i_gid = sb->s_root->d_inode->i_gid;
	}
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
337
	inode->i_ino = get_next_ino();
L
Linus Torvalds 已提交
338

339
	if (S_ISDIR(mode)) {
M
Miklos Szeredi 已提交
340
		set_nlink(inode, 2);
L
Linus Torvalds 已提交
341 342
		inode->i_op = &autofs4_dir_inode_operations;
		inode->i_fop = &autofs4_dir_operations;
343
	} else if (S_ISLNK(mode)) {
L
Linus Torvalds 已提交
344 345 346 347 348
		inode->i_op = &autofs4_symlink_inode_operations;
	}

	return inode;
}