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

📄 namespace.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/namespace.c * * (C) Copyright Al Viro 2000, 2001 *	Released under GPL v2. * * Based on code from fs/super.c, copyright Linus Torvalds and others. * Heavily rewritten. */#include <linux/config.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/quotaops.h>#include <linux/acct.h>#include <linux/module.h>#include <linux/devfs_fs_kernel.h>#include <asm/uaccess.h>#include <linux/seq_file.h>struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);int do_remount_sb(struct super_block *sb, int flags, void * data);void kill_super(struct super_block *sb);static struct list_head *mount_hashtable;static int hash_mask, hash_bits;static kmem_cache_t *mnt_cache; static LIST_HEAD(vfsmntlist);static DECLARE_MUTEX(mount_sem);/* Will be static */struct vfsmount *root_vfsmnt;static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry){	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);	tmp += ((unsigned long) dentry / L1_CACHE_BYTES);	tmp = tmp + (tmp >> hash_bits);	return tmp & hash_mask;}struct vfsmount *alloc_vfsmnt(void){	struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); 	if (mnt) {		memset(mnt, 0, sizeof(struct vfsmount));		atomic_set(&mnt->mnt_count,1);		INIT_LIST_HEAD(&mnt->mnt_hash);		INIT_LIST_HEAD(&mnt->mnt_child);		INIT_LIST_HEAD(&mnt->mnt_mounts);		INIT_LIST_HEAD(&mnt->mnt_list);	}	return mnt;}void free_vfsmnt(struct vfsmount *mnt){	if (mnt->mnt_devname)		kfree(mnt->mnt_devname);	kmem_cache_free(mnt_cache, mnt);}void set_devname(struct vfsmount *mnt, const char *name){	if (name) {		int size = strlen(name)+1;		char * newname = kmalloc(size, GFP_KERNEL);		if (newname) {			memcpy(newname, name, size);			mnt->mnt_devname = newname;		}	}}struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry){	struct list_head * head = mount_hashtable + hash(mnt, dentry);	struct list_head * tmp = head;	struct vfsmount *p;	for (;;) {		tmp = tmp->next;		p = NULL;		if (tmp == head)			break;		p = list_entry(tmp, struct vfsmount, mnt_hash);		if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry)			break;	}	return p;}static int check_mnt(struct vfsmount *mnt){	spin_lock(&dcache_lock);	while (mnt->mnt_parent != mnt)		mnt = mnt->mnt_parent;	spin_unlock(&dcache_lock);	return mnt == root_vfsmnt;}static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd){	old_nd->dentry = mnt->mnt_mountpoint;	old_nd->mnt = mnt->mnt_parent;	mnt->mnt_parent = mnt;	mnt->mnt_mountpoint = mnt->mnt_root;	list_del_init(&mnt->mnt_child);	list_del_init(&mnt->mnt_hash);	old_nd->dentry->d_mounted--;}static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd){	mnt->mnt_parent = mntget(nd->mnt);	mnt->mnt_mountpoint = dget(nd->dentry);	list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));	list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);	nd->dentry->d_mounted++;}static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root){	struct list_head *next = p->mnt_mounts.next;	if (next == &p->mnt_mounts) {		while (1) {			if (p == root)				return NULL;			next = p->mnt_child.next;			if (next != &p->mnt_parent->mnt_mounts)				break;			p = p->mnt_parent;		}	}	return list_entry(next, struct vfsmount, mnt_child);}static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root){	struct super_block *sb = old->mnt_sb;	struct vfsmount *mnt = alloc_vfsmnt();	if (mnt) {		mnt->mnt_flags = old->mnt_flags;		set_devname(mnt, old->mnt_devname);		atomic_inc(&sb->s_active);		mnt->mnt_sb = sb;		mnt->mnt_root = dget(root);		mnt->mnt_mountpoint = mnt->mnt_root;		mnt->mnt_parent = mnt;	}	return mnt;}void __mntput(struct vfsmount *mnt){	struct super_block *sb = mnt->mnt_sb;	dput(mnt->mnt_root);	free_vfsmnt(mnt);	kill_super(sb);}/* iterator */static void *m_start(struct seq_file *m, loff_t *pos){	struct list_head *p;	loff_t n = *pos;	down(&mount_sem);	list_for_each(p, &vfsmntlist)		if (!n--)			return list_entry(p, struct vfsmount, mnt_list);	return NULL;}static void *m_next(struct seq_file *m, void *v, loff_t *pos){	struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;	(*pos)++;	return p==&vfsmntlist ? NULL : list_entry(p, struct vfsmount, mnt_list);}static void m_stop(struct seq_file *m, void *v){	up(&mount_sem);}static inline void mangle(struct seq_file *m, const char *s){	seq_escape(m, s, " \t\n\\");}static int show_vfsmnt(struct seq_file *m, void *v){	struct vfsmount *mnt = v;	int err = 0;	static struct proc_fs_info {		int flag;		char *str;	} fs_info[] = {		{ MS_SYNCHRONOUS, ",sync" },		{ MS_MANDLOCK, ",mand" },		{ MS_NOATIME, ",noatime" },		{ MS_NODIRATIME, ",nodiratime" },		{ 0, NULL }	};	static struct proc_fs_info mnt_info[] = {		{ MNT_NOSUID, ",nosuid" },		{ MNT_NODEV, ",nodev" },		{ MNT_NOEXEC, ",noexec" },		{ 0, NULL }	};	struct proc_fs_info *fs_infop;	char *path_buf, *path;	path_buf = (char *) __get_free_page(GFP_KERNEL);	if (!path_buf)		return -ENOMEM;	path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");	seq_putc(m, ' ');	mangle(m, path);	free_page((unsigned long) path_buf);	seq_putc(m, ' ');	mangle(m, mnt->mnt_sb->s_type->name);	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {		if (mnt->mnt_sb->s_flags & fs_infop->flag)			seq_puts(m, fs_infop->str);	}	for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {		if (mnt->mnt_flags & fs_infop->flag)			seq_puts(m, fs_infop->str);	}	if (mnt->mnt_sb->s_op->show_options)		err = mnt->mnt_sb->s_op->show_options(m, mnt);	seq_puts(m, " 0 0\n");	return err;}struct seq_operations mounts_op = {	start:	m_start,	next:	m_next,	stop:	m_stop,	show:	show_vfsmnt};/* * Doesn't take quota and stuff into account. IOW, in some cases it will * give false negatives. The main reason why it's here is that we need * a non-destructive way to look for easily umountable filesystems. */int may_umount(struct vfsmount *mnt){	if (atomic_read(&mnt->mnt_count) > 2)		return -EBUSY;	return 0;}void umount_tree(struct vfsmount *mnt){	struct vfsmount *p;	LIST_HEAD(kill);	for (p = mnt; p; p = next_mnt(p, mnt)) {		list_del(&p->mnt_list);		list_add(&p->mnt_list, &kill);	}	while (!list_empty(&kill)) {		mnt = list_entry(kill.next, struct vfsmount, mnt_list);		list_del_init(&mnt->mnt_list);		if (mnt->mnt_parent == mnt) {			spin_unlock(&dcache_lock);		} else {			struct nameidata old_nd;			detach_mnt(mnt, &old_nd);			spin_unlock(&dcache_lock);			path_release(&old_nd);		}		mntput(mnt);		spin_lock(&dcache_lock);	}}static int do_umount(struct vfsmount *mnt, int flags){	struct super_block * sb = mnt->mnt_sb;	int retval = 0;	/*	 * If we may have to abort operations to get out of this	 * mount, and they will themselves hold resources we must	 * allow the fs to do things. In the Unix tradition of	 * 'Gee thats tricky lets do it in userspace' the umount_begin	 * might fail to complete on the first run through as other tasks	 * must return, and the like. Thats for the mount program to worry	 * about for the moment.	 */	lock_kernel();	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)		sb->s_op->umount_begin(sb);	unlock_kernel();	/*	 * No sense to grab the lock for this test, but test itself looks	 * somewhat bogus. Suggestions for better replacement?	 * Ho-hum... In principle, we might treat that as umount + switch	 * to rootfs. GC would eventually take care of the old vfsmount.	 * Actually it makes sense, especially if rootfs would contain a	 * /reboot - static binary that would close all descriptors and	 * call reboot(9). Then init(8) could umount root and exec /reboot.	 */	if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {		/*		 * Special case for "unmounting" root ...		 * we just try to remount it readonly.		 */		down_write(&sb->s_umount);		if (!(sb->s_flags & MS_RDONLY)) {			lock_kernel();			retval = do_remount_sb(sb, MS_RDONLY, 0);			unlock_kernel();		}		up_write(&sb->s_umount);		return retval;	}	down(&mount_sem);	spin_lock(&dcache_lock);	if (atomic_read(&sb->s_active) == 1) {		/* last instance - try to be smart */		spin_unlock(&dcache_lock);		lock_kernel();		DQUOT_OFF(sb);		acct_auto_close(sb->s_dev);		unlock_kernel();		spin_lock(&dcache_lock);	}	retval = -EBUSY;	if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {		if (!list_empty(&mnt->mnt_list))			umount_tree(mnt);		retval = 0;	}	spin_unlock(&dcache_lock);	up(&mount_sem);	return retval;}/* * Now umount can handle mount points as well as block devices. * This is important for filesystems which use unnamed block devices. * * We now support a flag for forced unmount like the other 'big iron' * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD */asmlinkage long sys_umount(char * name, int flags){	struct nameidata nd;	char *kname;	int retval;	kname = getname(name);	retval = PTR_ERR(kname);	if (IS_ERR(kname))		goto out;	retval = 0;	if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))		retval = path_walk(kname, &nd);	putname(kname);	if (retval)		goto out;	retval = -EINVAL;	if (nd.dentry != nd.mnt->mnt_root)		goto dput_and_out;	if (!check_mnt(nd.mnt))		goto dput_and_out;	retval = -EPERM;	if (!capable(CAP_SYS_ADMIN))		goto dput_and_out;	retval = do_umount(nd.mnt, flags);dput_and_out:	path_release(&nd);out:	return retval;}/* *	The 2.0 compatible umount. No flags.  */ asmlinkage long sys_oldumount(char * name){	return sys_umount(name,0);}static int mount_is_safe(struct nameidata *nd){	if (capable(CAP_SYS_ADMIN))		return 0;	return -EPERM;#ifdef notyet	if (S_ISLNK(nd->dentry->d_inode->i_mode))		return -EPERM;	if (nd->dentry->d_inode->i_mode & S_ISVTX) {		if (current->uid != nd->dentry->d_inode->i_uid)			return -EPERM;	}	if (permission(nd->dentry->d_inode, MAY_WRITE))		return -EPERM;	return 0;#endif}static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry){	struct vfsmount *p, *next, *q, *res;	struct nameidata nd;	p = mnt;	res = nd.mnt = q = clone_mnt(p, dentry);	if (!q)		goto Enomem;	q->mnt_parent = q;	q->mnt_mountpoint = p->mnt_mountpoint;	while ( (next = next_mnt(p, mnt)) != NULL) {		while (p != next->mnt_parent) {			p = p->mnt_parent;			q = q->mnt_parent;		}		p = next;		nd.mnt = q;		nd.dentry = p->mnt_mountpoint;		q = clone_mnt(p, p->mnt_root);		if (!q)			goto Enomem;		spin_lock(&dcache_lock);		list_add_tail(&q->mnt_list, &res->mnt_list);		attach_mnt(q, &nd);		spin_unlock(&dcache_lock);	}	return res;Enomem:	if (res) {		spin_lock(&dcache_lock);		umount_tree(res);		spin_unlock(&dcache_lock);	}	return NULL;}/* Will become static */int graft_tree(struct vfsmount *mnt, struct nameidata *nd){	int err;	if (mnt->mnt_sb->s_flags & MS_NOUSER)		return -EINVAL;	if (S_ISDIR(nd->dentry->d_inode->i_mode) !=	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))		return -ENOTDIR;	err = -ENOENT;	down(&nd->dentry->d_inode->i_zombie);	if (IS_DEADDIR(nd->dentry->d_inode))		goto out_unlock;	spin_lock(&dcache_lock);	if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) {		struct list_head head;		attach_mnt(mnt, nd);		list_add_tail(&head, &mnt->mnt_list);		list_splice(&head, vfsmntlist.prev);		mntget(mnt);		err = 0;	}	spin_unlock(&dcache_lock);out_unlock:	up(&nd->dentry->d_inode->i_zombie);	return err;}/* * do loopback mount. */static int do_loopback(struct nameidata *nd, char *old_name, int recurse){	struct nameidata old_nd;	struct vfsmount *mnt = NULL;	int err = mount_is_safe(nd);	if (err)		return err;	if (!old_name || !*old_name)		return -EINVAL;	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))		err = path_walk(old_name, &old_nd);	if (err)		return err;	down(&mount_sem);	err = -EINVAL;	if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) {		err = -ENOMEM;		if (recurse)			mnt = copy_tree(old_nd.mnt, old_nd.dentry);		else			mnt = clone_mnt(old_nd.mnt, old_nd.dentry);	}	if (mnt) {		err = graft_tree(mnt, nd);		if (err) {			spin_lock(&dcache_lock);			umount_tree(mnt);			spin_unlock(&dcache_lock);		} else			mntput(mnt);	}	up(&mount_sem);	path_release(&old_nd);	return err;}/* * change filesystem flags. dir should be a physical root of filesystem. * If you've mounted a non-root directory somewhere and want to do remount * on it - tough luck. */static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data){	int err;	struct super_block * sb = nd->mnt->mnt_sb;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	if (!check_mnt(nd->mnt))		return -EINVAL;	if (nd->dentry != nd->mnt->mnt_root)		return -EINVAL;	down_write(&sb->s_umount);	err = do_remount_sb(sb, flags, data);	if (!err)		nd->mnt->mnt_flags=mnt_flags;

⌨️ 快捷键说明

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