View | Details | Raw Unified | Return to bug 15839
Collapse All | Expand All

(-)linux-2.6.25.4.orig/fs/Kconfig (+11 lines)
Lines 598-603 Link Here
598
	  local network, you probably do not need an automounter, and can say
598
	  local network, you probably do not need an automounter, and can say
599
	  N here.
599
	  N here.
600
600
601
config SUBFS_FS
602
	tristate "Kernel subfs support"
603
	help
604
	  The subfs is a tool to automatically mount file systems on demand.
605
606
	  To use the subfs you need the user-space tools from
607
	  <http://submount.sourceforge.net/>.
608
609
	  To compile this support as a module, choose M here: the module will be
610
	  called subfs.
611
601
config FUSE_FS
612
config FUSE_FS
602
	tristate "Filesystem in Userspace support"
613
	tristate "Filesystem in Userspace support"
603
	help
614
	help
(-)linux-2.6.25.4.orig/fs/Makefile (+1 lines)
Lines 105-110 Link Here
105
obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
105
obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
106
obj-$(CONFIG_AUTOFS_FS)		+= autofs/
106
obj-$(CONFIG_AUTOFS_FS)		+= autofs/
107
obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
107
obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
108
obj-$(CONFIG_SUBFS_FS)		+= subfs.o
108
obj-$(CONFIG_ADFS_FS)		+= adfs/
109
obj-$(CONFIG_ADFS_FS)		+= adfs/
109
obj-$(CONFIG_FUSE_FS)		+= fuse/
110
obj-$(CONFIG_FUSE_FS)		+= fuse/
110
obj-$(CONFIG_UDF_FS)		+= udf/
111
obj-$(CONFIG_UDF_FS)		+= udf/
(-)linux-2.6.25.4.orig/fs/subfs.c (+468 lines)
Line 0 Link Here
1
/*
2
 *  subfs.c
3
 *
4
 *  Copyright (C) 2003-2004 Eugene S. Weiss <eweiss@sbclobal.net>
5
 *
6
 *  Distributed under the terms of the GNU General Public License version 2
7
 *  or above.
8
 */
9
10
#include <linux/init.h>
11
#include <linux/module.h>
12
#include <linux/kernel.h>
13
#include <linux/moduleparam.h>
14
#include <linux/pagemap.h>
15
#include <linux/fs.h>
16
#include <asm/atomic.h>
17
#include <asm/uaccess.h>
18
#include <linux/list.h>
19
#include <linux/mount.h>
20
#include <linux/mnt_namespace.h>
21
#include <linux/namei.h>
22
#include <linux/dcache.h>
23
#include <linux/sysfs.h>
24
#include <asm/semaphore.h>
25
#include <asm/signal.h>
26
#include <linux/signal.h>
27
#include <linux/sched.h>
28
#include <linux/version.h>
29
#include <linux/rcupdate.h>
30
31
#include "subfs.h"
32
33
MODULE_LICENSE("GPL");
34
MODULE_AUTHOR("Eugene S. Weiss");
35
36
37
/* get_subfs_vfsmount tries to find the vfsmount structure assigned to
38
 * the pending mount.  It looks for a vfsmount structure matching the
39
 * superblock pointer sent.  This is not ideal, but I don't know of
40
 * another way to find the structure without altering the code in the
41
 * mount routines.
42
 */
43
static struct vfsmount *get_subfs_vfsmount(struct super_block *sb)
44
{
45
	struct fs_struct *init_fs;
46
	struct list_head *entry, *head, *lh;
47
	struct vfsmount *mnt;
48
49
	/* Get the head of the global mount list from the init process. */
50
	/* Is there a better way? */
51
	init_fs = init_task.fs;
52
	head = &init_fs->root.mnt->mnt_list;
53
54
	/* Go through the list and look for a superblock pointer match. */
55
	list_for_each_safe(entry, lh, head) {
56
		mnt = list_entry(entry, struct vfsmount, mnt_list);
57
		if (mnt->mnt_sb == sb)
58
			return mnt;
59
	}
60
	ERR("subfs: Unable to find mount structure for superblock.\n");
61
	return NULL;		/* If there was no match */
62
}
63
64
65
/* Same as set_fs_pwd from namespace.c.  There's a problem with the
66
 * symbol.  When it is fixed, discard this.
67
 * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
68
 * It can block. Requires the big lock held.
69
 */
70
static void subfs_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
71
			     struct dentry *dentry)
72
{
73
	struct dentry *old_pwd;
74
	struct vfsmount *old_pwdmnt;
75
76
	write_lock(&fs->lock);
77
	old_pwd = fs->pwd.dentry;
78
	old_pwdmnt = fs->pwd.mnt;
79
	fs->pwd.mnt = mntget(mnt);
80
	fs->pwd.dentry = dget(dentry);
81
	write_unlock(&fs->lock);
82
83
	if (old_pwd) {
84
		dput(old_pwd);
85
		mntput(old_pwdmnt);
86
	}
87
}
88
89
90
/* Quickly sends an ignored signal to the signal handling system. This
91
 * causes the system to restart the system call when it receives the
92
 * -ERESTARTSYS error.
93
 */
94
static void subfs_send_signal(void)
95
{
96
	struct task_struct *task = current;
97
	int signal = SIGCONT;
98
99
	rcu_read_lock();
100
	spin_lock_irq(&task->sighand->siglock);
101
	sigaddset(&task->pending.signal, signal);
102
	spin_unlock_irq(&task->sighand->siglock);
103
	rcu_read_unlock();
104
	set_tsk_thread_flag(task, TIF_SIGPENDING);
105
	return;
106
}
107
108
109
/* If the option "procuid" is chosen when subfs is mounted, the uid
110
 * and gid numbers for the current process will  bea dded to the mount
111
 * option line.  Hence, non-unix filesystems will be mounted with
112
 * that ownership.
113
 */
114
static void add_procuid(struct subfs_mount *sfs_mnt)
115
{
116
	struct task_struct *task = current;
117
	char *o = kmalloc(strlen(sfs_mnt->options) + 1 + 32 + 1, GFP_KERNEL);
118
119
	if (sfs_mnt->options[0] == '\0')
120
		sprintf(o, "uid=%d,gid=%d", task->uid, task->gid);
121
	else
122
		sprintf(o, "%s,uid=%d,gid=%d", sfs_mnt->options, task->uid, task->gid);
123
124
	kfree(sfs_mnt->options);
125
	sfs_mnt->options = o;
126
}
127
128
129
/* This routine calls the /sbin/submountd program to mount the
130
 * appropriate filesystem on top of the subfs mount.  Returns
131
 * 0 if the userspace program exited normally, or an error if
132
 * it did not.
133
 */
134
static int mount_real_fs(struct subfs_mount *sfs_mnt)
135
{
136
	char *argv[7] =
137
	    { sfs_mnt->helper_prog, NULL, NULL, NULL, NULL, NULL, NULL };
138
	char *envp[2] = { "HOME=/", NULL };
139
	char *path_buf;
140
	int result, len = 0;
141
	struct path p;
142
143
	argv[1] = sfs_mnt->device;
144
	path_buf = (char *) __get_free_page(GFP_KERNEL);
145
	if (!path_buf)
146
		return -ENOMEM;
147
	p.mnt = sfs_mnt->mount;
148
	p.dentry = p.mnt->mnt_root;
149
	argv[2] = d_path(&p, path_buf, PAGE_SIZE);
150
	argv[3] = sfs_mnt->req_fs;
151
	if (!(argv[4] = kmalloc(17, GFP_KERNEL))) {
152
		free_page((unsigned long) path_buf);
153
		return -ENOMEM;	/* 64 bits on some platforms */
154
	}
155
	sprintf(argv[4], "%lx", sfs_mnt->flags);
156
	len = strlen(sfs_mnt->options);
157
	if (sfs_mnt->procuid)
158
		add_procuid(sfs_mnt);
159
	argv[5] = sfs_mnt->options;
160
	result = call_usermodehelper(sfs_mnt->helper_prog, argv, envp, 1);
161
	free_page((unsigned long) path_buf);
162
	kfree(argv[4]);
163
	if (sfs_mnt->procuid)
164
		sfs_mnt->options[len] = '\0';
165
	return result;
166
}
167
168
169
/*  This routine returns a pointer to the filesystem mounted on top
170
 *	of the subfs mountpoint, or an error pointer if it was unable to.
171
 */
172
static struct vfsmount *get_child_mount(struct subfs_mount *sfs_mnt)
173
{
174
	struct vfsmount *child;
175
	int result;
176
        /* First time: find the vfsmount structure that matches sfs_mnt. */
177
	if (!sfs_mnt->mount) {
178
		if(!(sfs_mnt->mount = get_subfs_vfsmount(sfs_mnt->sb)))
179
			return ERR_PTR(-ENOMEDIUM);
180
		sfs_mnt->flags = sfs_mnt->sb->s_flags;
181
		if (sfs_mnt->mount->mnt_flags & MNT_NOSUID)
182
			sfs_mnt->flags |= MS_NOSUID;
183
		if (sfs_mnt->mount->mnt_flags & MNT_NODEV)
184
			sfs_mnt->flags |= MS_NODEV;
185
		if (sfs_mnt->mount->mnt_flags & MNT_NOEXEC)
186
			sfs_mnt->flags |= MS_NOEXEC;
187
	}
188
	/* Check to see if a child mount does not already exist. */
189
	if (&sfs_mnt->mount->mnt_mounts == sfs_mnt->mount->mnt_mounts.next) {
190
		result = mount_real_fs(sfs_mnt);
191
		if (result) {
192
			ERR("subfs: "SUBMOUNTD_PATH" unsuccessful attempt to mount media (%d)\n",
193
			       result);
194
			/* Workaround for call_usermodehelper return value bug. */
195
			if(result < 0)
196
				return ERR_PTR(result);
197
			return ERR_PTR(-ENOMEDIUM);
198
		}
199
		if (&sfs_mnt->mount->mnt_mounts
200
				== sfs_mnt->mount->mnt_mounts.next) {
201
			ERR("subfs: submountd mount failure.\n");
202
			return ERR_PTR(-ENOMEDIUM);
203
		}
204
	}
205
	child = list_entry(sfs_mnt->mount->mnt_mounts.next,
206
			   struct vfsmount, mnt_child);
207
	return child;
208
}
209
210
211
/* Implements the lookup method for subfs.  Tries to get the child
212
 * mount.  If it succeeds, it emits a signal and returns
213
 * -ERESTARSYS.  If it receives an error, it passes it on to the
214
 * system. It raises the semaphore in the directory inode before mounting
215
 * because the mount routine also calls lookup, and hence a function is
216
 * calling itself from within semaphore protected code.  Only the semaphore
217
 * on the subfs pseudo-directory is effected, so this isn't deadly.
218
 */
219
static struct dentry *subfs_lookup(struct inode *dir,
220
				struct dentry *dentry, struct nameidata *nd)
221
{
222
	struct subfs_mount *sfs_mnt = dir->i_sb->s_fs_info;
223
	struct vfsmount *child;
224
225
	/* This is ugly, but prevents a lockup during mount. */
226
	mutex_unlock(&dir->i_mutex);
227
	if (down_interruptible(&sfs_mnt->sem)) {
228
		mutex_lock(&dir->i_mutex); /* put the dir sem back down if interrupted */
229
		return ERR_PTR(-ERESTARTSYS);
230
	}
231
	child = get_child_mount(sfs_mnt);
232
	up(&sfs_mnt->sem);
233
	mutex_lock(&dir->i_mutex);
234
	if (IS_ERR(child))
235
		return (void *) child;
236
	subfs_send_signal();
237
	if (sfs_mnt->mount == current->fs->pwd.mnt)
238
		subfs_set_fs_pwd(current->fs, child, child->mnt_root);
239
	return ERR_PTR(-ERESTARTSYS);
240
}
241
242
243
/* Implements the open method for subfs.  Tries to get the child mount
244
 * for the subfs mountpoint which is being opened.  Returns -ERESTARTSYS
245
 * and emits an ignored signal to the calling process if it succeeds,
246
 * or passes the error message received if it fails.
247
 */
248
static int subfs_open(struct inode *inode, struct file *filp)
249
{
250
	struct subfs_mount *sfs_mnt = filp->f_dentry->d_sb->s_fs_info;
251
	struct vfsmount *child;
252
	if (down_interruptible(&sfs_mnt->sem))
253
		return -ERESTARTSYS;
254
	child = get_child_mount(sfs_mnt);
255
	up(&sfs_mnt->sem);
256
	if (IS_ERR(child))
257
		return PTR_ERR(child);
258
	subfs_send_signal();
259
	if (sfs_mnt->mount == current->fs->pwd.mnt)
260
		subfs_set_fs_pwd(current->fs, child, child->mnt_root);
261
	return -ERESTARTSYS;
262
}
263
264
265
/*  Implements the statfs method so df and such will work on the mountpoint.
266
 */
267
static int subfs_statfs(struct dentry *dentry, struct kstatfs *buf)
268
{
269
	struct subfs_mount *sfs_mnt = dentry->d_sb->s_fs_info;
270
	struct vfsmount *child;
271
	if (down_interruptible(&sfs_mnt->sem))
272
		return -ERESTARTSYS;
273
	child = get_child_mount(sfs_mnt);
274
	up(&sfs_mnt->sem);
275
	if (IS_ERR(child))
276
		return PTR_ERR(child);
277
	subfs_send_signal();
278
	return -ERESTARTSYS;
279
}
280
281
282
/*  Creates the inodes for subfs superblocks.
283
 */
284
static struct inode *subfs_make_inode(struct super_block *sb, int mode)
285
{
286
	struct inode *ret = new_inode(sb);
287
288
	if (ret) {
289
		ret->i_mode = mode;
290
		ret->i_uid = ret->i_gid = 0;
291
		ret->i_blocks = 0;
292
		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
293
		ret->i_fop = &subfs_file_ops;
294
	}
295
	return ret;
296
}
297
298
299
/*  Fills the fields for the superblock created when subfs is mounted.
300
 */
301
static int subfs_fill_super(struct super_block *sb, void *data, int silent)
302
{
303
	struct inode *root;
304
	struct dentry *root_dentry;
305
306
	sb->s_blocksize = PAGE_CACHE_SIZE;
307
	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
308
	sb->s_magic = SUBFS_MAGIC;
309
	sb->s_op = &subfs_s_ops;
310
	root = subfs_make_inode(sb, S_IFDIR|ROOT_MODE);
311
	if (!root)
312
		goto out;
313
	root->i_op = &subfs_dir_inode_operations;
314
	root_dentry = d_alloc_root(root);
315
	if (!root_dentry)
316
		goto out_iput;
317
	sb->s_root = root_dentry;
318
	return 0;
319
      out_iput:
320
	iput(root);
321
      out:
322
	return -ENOMEM;
323
}
324
325
326
/* Parse the options string and remove submount specific options
327
 * and store the appropriate data.
328
 */
329
static int proc_opts(struct subfs_mount *sfs_mnt, void *data)
330
{
331
	char *opts = data, *opt, *ptr, *fs = NULL, *prog;
332
	int len;
333
334
	if (!opts) {
335
		if (!(data = opts = kmalloc(PAGE_SIZE, GFP_KERNEL)))
336
			return -EINVAL;
337
		strcat(opts, "fs=auto");
338
	}
339
	len = strnlen(opts, PAGE_SIZE - 1) + 1;
340
	if (strstr(opts, "procuid"))
341
		sfs_mnt->procuid = 1;
342
	if (!(sfs_mnt->options = kmalloc(len, GFP_KERNEL)))
343
		return -ENOMEM;
344
	sfs_mnt->options[0] = '\0';
345
	while ((opt = strsep(&opts, ","))) {
346
        	if ((ptr = strstr(opt, "program="))) {
347
                	if (!(prog = kmalloc((strlen(ptr) - 7), GFP_KERNEL)))
348
                        	return -ENOMEM;
349
			strcpy(prog, (ptr + 8));
350
                        kfree(sfs_mnt->helper_prog);
351
                        sfs_mnt->helper_prog = prog;
352
		}
353
		else if ((ptr = strstr(opt, "fs="))) {
354
			if (!(fs = kmalloc((strlen(ptr) - 2), GFP_KERNEL)))
355
				return -ENOMEM;
356
			strcpy(fs, (ptr + 3));
357
			sfs_mnt->req_fs = fs;
358
		}
359
		else if ((ptr = strstr(opt, "procuid"))) {
360
		} else {
361
			strncat(sfs_mnt->options, opt, 32);
362
			strcat(sfs_mnt->options, ",");
363
		}
364
	}
365
	if((len = strlen(sfs_mnt->options)) && (sfs_mnt->options[len-1] == ','))
366
		sfs_mnt->options[len-1] = '\0';
367
	if ( !sfs_mnt->req_fs ){
368
		if (!(sfs_mnt->req_fs = kmalloc(5, GFP_KERNEL)))
369
			return -ENOMEM;	/* 64 bits on some platforms */
370
		strcpy(sfs_mnt->req_fs, "auto" );
371
	}
372
	return 0;
373
}
374
375
376
377
/* subfs_get_super is the subfs implementation of the get_sb method on
378
 * the file_system_type structure.  It should only be called in the
379
 * case of a mount.  It creates a new subfs_mount structure, fills
380
 * the fields of the structure, except for the mount structure, and then
381
 * calls a generic get_sb function.  The superblock pointer is stored on
382
 * the subfs_mount structure, and returned to the calling function.  The
383
 * subfs_mount structure is pointed to by the s_fs_info field of the
384
 * superblock structure.
385
 */
386
static int subfs_get_super(struct file_system_type *fst,
387
				int flags, const char *devname, void *data,
388
				struct vfsmount *mnt)
389
{
390
	char *device;
391
	struct subfs_mount *newmount;
392
	int ret;
393
394
	if (!(newmount = kmalloc(sizeof(struct subfs_mount), GFP_KERNEL))) {
395
		ret = -ENOMEM;
396
		goto err;
397
	}
398
	newmount->req_fs = NULL;
399
	newmount->sb = NULL;
400
	newmount->mount = NULL;
401
	newmount->procuid = 0;
402
	sema_init(&newmount->sem, 1);
403
	if (!(device = kmalloc((strlen(devname) + 1), GFP_KERNEL))) {
404
		ret = -ENOMEM;
405
		goto err;
406
	}
407
	strcpy(device, devname);
408
	newmount->device = device;
409
        if (!(newmount->helper_prog =
410
        		kmalloc(sizeof(SUBMOUNTD_PATH), GFP_KERNEL))) {
411
			ret = -ENOMEM;
412
			goto err;
413
		}
414
	strcpy(newmount->helper_prog, SUBMOUNTD_PATH);
415
	if ((ret = proc_opts(newmount, data)))
416
		goto err;
417
	ret = get_sb_nodev(fst, flags, data, subfs_fill_super, mnt);
418
	if (ret)
419
		goto err;
420
	newmount->sb = mnt->mnt_sb;
421
	newmount->sb->s_fs_info = newmount;
422
	return ret;
423
424
err:
425
	return ret;
426
}
427
428
429
/* subfs_kill_super is the subfs implementation of the kill_sb method.
430
 * It should be called only on umount.  It cleans up the appropriate
431
 * subfs_mount structure and then calls a generic function to actually
432
 * clean up the superblock structure.
433
 */
434
static void subfs_kill_super(struct super_block *sb)
435
{
436
	struct subfs_mount *sfs_mnt = sb->s_fs_info;
437
438
        if(sfs_mnt) {
439
		if (sfs_mnt->device)
440
			kfree(sfs_mnt->device);
441
		if (sfs_mnt->options)
442
			kfree(sfs_mnt->options);
443
		if (sfs_mnt->req_fs)
444
			kfree(sfs_mnt->req_fs);
445
		if (sfs_mnt->helper_prog)
446
                	kfree(sfs_mnt->helper_prog);
447
		kfree(sfs_mnt);
448
        	sb->s_fs_info = NULL;
449
	}
450
	kill_litter_super(sb);
451
	return;
452
}
453
454
455
static int __init subfs_init(void)
456
{
457
	printk(KERN_INFO "subfs %s\n", SUBFS_VER);
458
	return register_filesystem(&subfs_type);
459
}
460
461
static void __exit subfs_exit(void)
462
{
463
	printk(KERN_INFO "subfs exiting.\n");
464
	unregister_filesystem(&subfs_type);
465
}
466
467
module_init(subfs_init);
468
module_exit(subfs_exit);
(-)linux-2.6.25.4.orig/fs/subfs.h (+76 lines)
Line 0 Link Here
1
/*
2
 *  subfs.h
3
 *
4
 *  Copyright (C) 2003-2004 Eugene S. Weiss <eweiss@sbclobal.net>
5
 *
6
 *  Distributed under the terms of the GNU General Public License version 2
7
 *  or above.
8
 */
9
10
11
#define SUBFS_MAGIC 0x2c791058
12
13
#define SUBMOUNTD_PATH "/sbin/submountd"
14
15
#define ERR(args...) \
16
	printk(KERN_ERR args)
17
18
#define SUBFS_VER "0.9"
19
20
#define ROOT_MODE 0777
21
22
struct subfs_mount {
23
	char *device;
24
	char *options;
25
	char *req_fs;
26
        char *helper_prog;
27
	unsigned long flags;
28
	struct super_block *sb;
29
	struct vfsmount *mount;
30
	struct semaphore sem;
31
	int procuid;
32
};
33
34
35
static void subfs_kill_super(struct super_block *sb);
36
37
static int subfs_get_super(struct file_system_type *fst,
38
		int flags, const char *devname, void *data, struct vfsmount *mnt);
39
static int subfs_statfs(struct dentry *dentry, struct kstatfs *buf);
40
41
static struct vfsmount *get_subfs_vfsmount(struct super_block *sb);
42
static int subfs_fill_super(struct super_block *sb, void *data,
43
			    int silent);
44
static struct inode *subfs_make_inode(struct super_block *sb, int mode);
45
static int subfs_open(struct inode *inode, struct file *filp);
46
static struct dentry *subfs_lookup(struct inode *dir,
47
				   struct dentry *dentry, struct nameidata *nd);
48
static struct vfsmount *get_child_mount(struct subfs_mount *sfs_mnt);
49
static int mount_real_fs(struct subfs_mount *sfs_mnt);
50
static void subfs_send_signal(void);
51
static void subfs_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
52
			     struct dentry *dentry);
53
54
55
static struct file_system_type subfs_type = {
56
	.owner = THIS_MODULE,
57
	.name = "subfs",
58
	.get_sb = subfs_get_super,
59
	.kill_sb = subfs_kill_super,
60
};
61
62
63
static struct super_operations subfs_s_ops = {
64
	.statfs = subfs_statfs,
65
	.drop_inode = generic_delete_inode,
66
};
67
68
69
static struct inode_operations subfs_dir_inode_operations = {
70
	.lookup = subfs_lookup,
71
};
72
73
74
static struct file_operations subfs_file_ops = {
75
	.open = subfs_open,
76
};

Return to bug 15839