⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 super.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/super.c * *  Copyright (C) 1991, 1992  Linus Torvalds * *  super.c contains code to handle: - mount structures *                                   - super-block tables *                                   - filesystem drivers list *                                   - mount system call *                                   - umount system call *                                   - ustat system call * * GK 2/5/95  -  Changed to support mounting the root fs via NFS * *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96 *  Added options to /proc/mounts: *    Torbj鰎n Lindh (torbjorn.lindh@gopta.se), April 14, 1996. *  Added devfs support: Richard Gooch <rgooch@atnf.csiro.au>, 13-JAN-1998 *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000 */#include <linux/config.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/locks.h>#include <linux/smp_lock.h>#include <linux/devfs_fs_kernel.h>#include <linux/fd.h>#include <linux/init.h>#include <linux/major.h>#include <linux/quotaops.h>#include <linux/acct.h>#include <asm/uaccess.h>#include <linux/nfs_fs.h>#include <linux/nfs_fs_sb.h>#include <linux/nfs_mount.h>#include <linux/kmod.h>#define __NO_VERSION__#include <linux/module.h>extern void wait_for_keypress(void);extern int root_mountflags;int do_remount_sb(struct super_block *sb, int flags, void * data);/* this is initialized in init/main.c */kdev_t ROOT_DEV;LIST_HEAD(super_blocks);spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;/* * 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_inc_mod_count(); 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 rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;/* WARNING: This can be used only if we _already_ own a reference */static void get_filesystem(struct file_system_type *fs){	if (fs->owner)		__MOD_INC_USE_COUNT(fs->owner);}static void put_filesystem(struct file_system_type *fs){	if (fs->owner)		__MOD_DEC_USE_COUNT(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;}/** *	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;}static int fs_index(const char * __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 * 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_inc_mod_count(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 *) arg1);			break;		case 2:			retval = fs_name(arg1, (char *) 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_inc_mod_count(fs->owner))		fs = NULL;	read_unlock(&file_systems_lock);	if (!fs && (request_module(name) == 0)) {		read_lock(&file_systems_lock);		fs = *(find_filesystem(name));		if (fs && !try_inc_mod_count(fs->owner))			fs = NULL;		read_unlock(&file_systems_lock);	}	return fs;}/** *	alloc_super	-	create new superblock * *	Allocates and initializes a new &struct super_block.  alloc_super() *	returns a pointer new superblock or %NULL if allocation had failed. */static struct super_block *alloc_super(void){	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);	if (s) {		memset(s, 0, sizeof(struct super_block));		INIT_LIST_HEAD(&s->s_dirty);		INIT_LIST_HEAD(&s->s_locked_inodes);		INIT_LIST_HEAD(&s->s_files);		INIT_LIST_HEAD(&s->s_instances);		init_rwsem(&s->s_umount);		sema_init(&s->s_lock, 1);		down_write(&s->s_umount);		s->s_count = S_BIAS;		atomic_set(&s->s_active, 1);		sema_init(&s->s_vfs_rename_sem,1);		sema_init(&s->s_nfsd_free_path_sem,1);		sema_init(&s->s_dquot.dqio_sem, 1);		sema_init(&s->s_dquot.dqoff_sem, 1);		s->s_maxbytes = MAX_NON_LFS;	}	return s;}/** *	destroy_super	-	frees a superblock *	@s: superblock to free * *	Frees a superblock. */static inline void destroy_super(struct super_block *s){	kfree(s);}/* Superblock refcounting  *//** *	deactivate_super	-	turn an active reference into temporary *	@s: superblock to deactivate * *	Turns an active reference into temporary one.  Returns 0 if there are *	other active references, 1 if we had deactivated the last one. */static inline int deactivate_super(struct super_block *s){	if (!atomic_dec_and_lock(&s->s_active, &sb_lock))		return 0;	s->s_count -= S_BIAS-1;	spin_unlock(&sb_lock);	return 1;}/** *	put_super	-	drop a temporary reference to superblock *	@s: superblock in question * *	Drops a temporary reference, frees superblock if there's no *	references left. */static inline void put_super(struct super_block *s){	spin_lock(&sb_lock);	if (!--s->s_count)		destroy_super(s);	spin_unlock(&sb_lock);}/** *	grab_super	- acquire an active reference *	@s	- reference we are trying to make active * *	Tries to acquire an active reference.  grab_super() is used when we * 	had just found a superblock in super_blocks or fs_type->fs_supers *	and want to turn it into a full-blown active reference.  grab_super() *	is called with sb_lock held and drops it.  Returns 1 in case of *	success, 0 if we had failed (superblock contents was already dead or *	dying when grab_super() had been called). */static int grab_super(struct super_block *s){	s->s_count++;	spin_unlock(&sb_lock);	down_write(&s->s_umount);	if (s->s_root) {		spin_lock(&sb_lock);		if (s->s_count > S_BIAS) {			atomic_inc(&s->s_active);			s->s_count--;			spin_unlock(&sb_lock);			return 1;		}		spin_unlock(&sb_lock);	}	up_write(&s->s_umount);	put_super(s);	return 0;} /** *	insert_super	-	put superblock on the lists *	@s:	superblock in question *	@type:	filesystem type it will belong to * *	Associates superblock with fs type and puts it on per-type and global *	superblocks' lists.  Should be called with sb_lock held; drops it. */static void insert_super(struct super_block *s, struct file_system_type *type){	s->s_type = type;	list_add(&s->s_list, super_blocks.prev);	list_add(&s->s_instances, &type->fs_supers);	spin_unlock(&sb_lock);	get_filesystem(type);}void put_unnamed_dev(kdev_t dev);	/* should become static *//** *	remove_super	-	makes superblock unreachable *	@s:	superblock in question * *	Removes superblock from the lists, unlocks it, drop the reference *	and releases the hosting device.  @s should have no active *	references by that time and after remove_super() it's essentially *	in rundown mode - all remaining references are temporary, no new *	reference of any sort are going to appear and all holders of *	temporary ones will eventually drop them.  At that point superblock *	itself will be destroyed; all its contents is already gone. */static void remove_super(struct super_block *s){	kdev_t dev = s->s_dev;	struct block_device *bdev = s->s_bdev;	struct file_system_type *fs = s->s_type;	spin_lock(&sb_lock);	list_del(&s->s_list);	list_del(&s->s_instances);	spin_unlock(&sb_lock);	up_write(&s->s_umount);	put_super(s);	put_filesystem(fs);	if (bdev)		blkdev_put(bdev, BDEV_FS);	else		put_unnamed_dev(dev);}struct vfsmount *alloc_vfsmnt(void);void free_vfsmnt(struct vfsmount *mnt);void set_devname(struct vfsmount *mnt, const char *name);/* Will go away */extern struct vfsmount *root_vfsmnt;extern int graft_tree(struct vfsmount *mnt, struct nameidata *nd);static inline struct super_block * find_super(kdev_t dev){	struct list_head *p;	list_for_each(p, &super_blocks) {		struct super_block * s = sb_entry(p);		if (s->s_dev == dev) {			s->s_count++;			return s;		}	}	return NULL;}void drop_super(struct super_block *sb){	up_read(&sb->s_umount);	put_super(sb);}static inline void write_super(struct super_block *sb){	lock_super(sb);	if (sb->s_root && sb->s_dirt)		if (sb->s_op && sb->s_op->write_super)			sb->s_op->write_super(sb);	unlock_super(sb);}/* * Note: check the dirty flag before waiting, so we don't * hold up the sync while mounting a device. (The newly * mounted device won't need syncing.) */void sync_supers(kdev_t dev){	struct super_block * sb;	if (dev) {		sb = get_super(dev);		if (sb) {			if (sb->s_dirt)				write_super(sb);			drop_super(sb);		}		return;	}restart:	spin_lock(&sb_lock);	sb = sb_entry(super_blocks.next);	while (sb != sb_entry(&super_blocks))		if (sb->s_dirt) {			sb->s_count++;			spin_unlock(&sb_lock);			down_read(&sb->s_umount);			write_super(sb);			drop_super(sb);			goto restart;		} else			sb = sb_entry(sb->s_list.next);	spin_unlock(&sb_lock);}/** *	get_super	-	get the superblock of a device *	@dev: device to get the superblock for *	 *	Scans the superblock list and finds the superblock of the file system *	mounted on the device given. %NULL is returned if no match is found. */ struct super_block * get_super(kdev_t dev){	struct super_block * s;	if (!dev)		return NULL;restart:	spin_lock(&sb_lock);	s = find_super(dev);	if (s) {		spin_unlock(&sb_lock);		down_read(&s->s_umount);		if (s->s_root)			return s;		drop_super(s);		goto restart;	}	spin_unlock(&sb_lock);	return NULL;}asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf){        struct super_block *s;        struct ustat tmp;        struct statfs sbuf;	int err = -EINVAL;        s = get_super(to_kdev_t(dev));        if (s == NULL)                goto out;	err = vfs_statfs(s, &sbuf);	drop_super(s);	if (err)		goto out;        memset(&tmp,0,sizeof(struct ustat));        tmp.f_tfree = sbuf.f_bfree;        tmp.f_tinode = sbuf.f_ffree;        err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;out:	return err;}static struct super_block * read_super(kdev_t dev, struct block_device *bdev,				       struct file_system_type *type, int flags,				       void *data){	struct super_block * s;	s = alloc_super();	if (!s)		goto out;	s->s_dev = dev;	s->s_bdev = bdev;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -