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>
22
#include <linux/compat.h>
L
Linus Torvalds 已提交
23 24 25
#include "autofs_i.h"
#include <linux/module.h>

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

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

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

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

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

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

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

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

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

	if (!sbi)
		return 0;

	seq_printf(m, ",fd=%d", sbi->pipefd);
M
Miklos Szeredi 已提交
83 84 85 86
	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);
87 88 89 90 91
	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);

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

99 100 101
	return 0;
}

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

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

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

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

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

137 138
	*uid = current_uid();
	*gid = current_gid();
P
Pavel Emelianov 已提交
139
	*pgrp = task_pgrp_nr(current);
L
Linus Torvalds 已提交
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 184

	*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;
185
		case Opt_indirect:
186
			set_autofs_type_indirect(type);
187 188
			break;
		case Opt_direct:
189
			set_autofs_type_direct(type);
190 191
			break;
		case Opt_offset:
192
			set_autofs_type_offset(type);
193
			break;
L
Linus Torvalds 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
		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;

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

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

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

	root->d_fsdata = ino;
L
Linus Torvalds 已提交
256 257

	/* Can this call block? */
258 259 260
	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 已提交
261 262 263 264
		printk("autofs: called with bogus options\n");
		goto fail_dput;
	}

265
	if (autofs_type_trigger(sbi->type))
266
		__managed_dentry_set_managed(root);
267

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

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

281 282 283 284 285
	/* 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 已提交
286 287 288 289 290
	sbi->sub_version = AUTOFS_PROTO_SUBVERSION;

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

	/*
	 * 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;
317 318
fail_ino:
	kfree(ino);
L
Linus Torvalds 已提交
319 320
fail_free:
	kfree(sbi);
I
Ian Kent 已提交
321
	s->s_fs_info = NULL;
L
Linus Torvalds 已提交
322 323 324 325
fail_unlock:
	return -EINVAL;
}

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

	if (inode == NULL)
		return NULL;

333
	inode->i_mode = mode;
L
Linus Torvalds 已提交
334 335 336 337 338
	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;
339
	inode->i_ino = get_next_ino();
L
Linus Torvalds 已提交
340

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

	return inode;
}