diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/filesystems.c | |
| download | olio-linux-3.10-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.xz olio-linux-3.10-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.zip  | |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/filesystems.c')
| -rw-r--r-- | fs/filesystems.c | 236 | 
1 files changed, 236 insertions, 0 deletions
diff --git a/fs/filesystems.c b/fs/filesystems.c new file mode 100644 index 00000000000..44082bfdfec --- /dev/null +++ b/fs/filesystems.c @@ -0,0 +1,236 @@ +/* + *  linux/fs/filesystems.c + * + *  Copyright (C) 1991, 1992  Linus Torvalds + * + *  table of configured filesystems + */ + +#include <linux/syscalls.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/uaccess.h> + +/* + * Handling of filesystem drivers list. + * Rules: + *	Inclusion to/removals from/scanning of list are protected by spinlock. + *	During the unload module must call unregister_filesystem(). + *	We can access the fields of list element if: + *		1) spinlock is held or + *		2) we hold the reference to the module. + *	The latter can be guaranteed by call of try_module_get(); if it + *	returned 0 we must skip the element, otherwise we got the reference. + *	Once the reference is obtained we can drop the spinlock. + */ + +static struct file_system_type *file_systems; +static DEFINE_RWLOCK(file_systems_lock); + +/* WARNING: This can be used only if we _already_ own a reference */ +void get_filesystem(struct file_system_type *fs) +{ +	__module_get(fs->owner); +} + +void put_filesystem(struct file_system_type *fs) +{ +	module_put(fs->owner); +} + +static struct file_system_type **find_filesystem(const char *name) +{ +	struct file_system_type **p; +	for (p=&file_systems; *p; p=&(*p)->next) +		if (strcmp((*p)->name,name) == 0) +			break; +	return p; +} + +/** + *	register_filesystem - register a new filesystem + *	@fs: the file system structure + * + *	Adds the file system passed to the list of file systems the kernel + *	is aware of for mount and other syscalls. Returns 0 on success, + *	or a negative errno code on an error. + * + *	The &struct file_system_type that is passed is linked into the kernel  + *	structures and must not be freed until the file system has been + *	unregistered. + */ +  +int register_filesystem(struct file_system_type * fs) +{ +	int res = 0; +	struct file_system_type ** p; + +	if (!fs) +		return -EINVAL; +	if (fs->next) +		return -EBUSY; +	INIT_LIST_HEAD(&fs->fs_supers); +	write_lock(&file_systems_lock); +	p = find_filesystem(fs->name); +	if (*p) +		res = -EBUSY; +	else +		*p = fs; +	write_unlock(&file_systems_lock); +	return res; +} + +EXPORT_SYMBOL(register_filesystem); + +/** + *	unregister_filesystem - unregister a file system + *	@fs: filesystem to unregister + * + *	Remove a file system that was previously successfully registered + *	with the kernel. An error is returned if the file system is not found. + *	Zero is returned on a success. + *	 + *	Once this function has returned the &struct file_system_type structure + *	may be freed or reused. + */ +  +int unregister_filesystem(struct file_system_type * fs) +{ +	struct file_system_type ** tmp; + +	write_lock(&file_systems_lock); +	tmp = &file_systems; +	while (*tmp) { +		if (fs == *tmp) { +			*tmp = fs->next; +			fs->next = NULL; +			write_unlock(&file_systems_lock); +			return 0; +		} +		tmp = &(*tmp)->next; +	} +	write_unlock(&file_systems_lock); +	return -EINVAL; +} + +EXPORT_SYMBOL(unregister_filesystem); + +static int fs_index(const char __user * __name) +{ +	struct file_system_type * tmp; +	char * name; +	int err, index; + +	name = getname(__name); +	err = PTR_ERR(name); +	if (IS_ERR(name)) +		return err; + +	err = -EINVAL; +	read_lock(&file_systems_lock); +	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { +		if (strcmp(tmp->name,name) == 0) { +			err = index; +			break; +		} +	} +	read_unlock(&file_systems_lock); +	putname(name); +	return err; +} + +static int fs_name(unsigned int index, char __user * buf) +{ +	struct file_system_type * tmp; +	int len, res; + +	read_lock(&file_systems_lock); +	for (tmp = file_systems; tmp; tmp = tmp->next, index--) +		if (index <= 0 && try_module_get(tmp->owner)) +			break; +	read_unlock(&file_systems_lock); +	if (!tmp) +		return -EINVAL; + +	/* OK, we got the reference, so we can safely block */ +	len = strlen(tmp->name) + 1; +	res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0; +	put_filesystem(tmp); +	return res; +} + +static int fs_maxindex(void) +{ +	struct file_system_type * tmp; +	int index; + +	read_lock(&file_systems_lock); +	for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++) +		; +	read_unlock(&file_systems_lock); +	return index; +} + +/* + * Whee.. Weird sysv syscall.  + */ +asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) +{ +	int retval = -EINVAL; + +	switch (option) { +		case 1: +			retval = fs_index((const char __user *) arg1); +			break; + +		case 2: +			retval = fs_name(arg1, (char __user *) arg2); +			break; + +		case 3: +			retval = fs_maxindex(); +			break; +	} +	return retval; +} + +int get_filesystem_list(char * buf) +{ +	int len = 0; +	struct file_system_type * tmp; + +	read_lock(&file_systems_lock); +	tmp = file_systems; +	while (tmp && len < PAGE_SIZE - 80) { +		len += sprintf(buf+len, "%s\t%s\n", +			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", +			tmp->name); +		tmp = tmp->next; +	} +	read_unlock(&file_systems_lock); +	return len; +} + +struct file_system_type *get_fs_type(const char *name) +{ +	struct file_system_type *fs; + +	read_lock(&file_systems_lock); +	fs = *(find_filesystem(name)); +	if (fs && !try_module_get(fs->owner)) +		fs = NULL; +	read_unlock(&file_systems_lock); +	if (!fs && (request_module("%s", name) == 0)) { +		read_lock(&file_systems_lock); +		fs = *(find_filesystem(name)); +		if (fs && !try_module_get(fs->owner)) +			fs = NULL; +		read_unlock(&file_systems_lock); +	} +	return fs; +} + +EXPORT_SYMBOL(get_fs_type);  |