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

📄 namespace.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
	up_write(&sb->s_umount);	return err;}static int do_move_mount(struct nameidata *nd, char *old_name){	struct nameidata old_nd, parent_nd;	struct vfsmount *p;	int err = 0;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	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);	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))		;	err = -EINVAL;	if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt))		goto out;	err = -ENOENT;	down(&nd->dentry->d_inode->i_zombie);	if (IS_DEADDIR(nd->dentry->d_inode))		goto out1;	spin_lock(&dcache_lock);	if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))		goto out2;	err = -EINVAL;	if (old_nd.dentry != old_nd.mnt->mnt_root)		goto out2;	if (old_nd.mnt == old_nd.mnt->mnt_parent)		goto out2;	if (S_ISDIR(nd->dentry->d_inode->i_mode) !=	      S_ISDIR(old_nd.dentry->d_inode->i_mode))		goto out2;	err = -ELOOP;	for (p = nd->mnt; p->mnt_parent!=p; p = p->mnt_parent)		if (p == old_nd.mnt)			goto out2;	err = 0;	detach_mnt(old_nd.mnt, &parent_nd);	attach_mnt(old_nd.mnt, nd);out2:	spin_unlock(&dcache_lock);out1:	up(&nd->dentry->d_inode->i_zombie);out:	up(&mount_sem);	if (!err)		path_release(&parent_nd);	path_release(&old_nd);	return err;}static int do_add_mount(struct nameidata *nd, char *type, int flags,			int mnt_flags, char *name, void *data){	struct vfsmount *mnt = do_kern_mount(type, flags, name, data);	int err = PTR_ERR(mnt);	if (IS_ERR(mnt))		goto out;	down(&mount_sem);	/* Something was mounted here while we slept */	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))		;	err = -EINVAL;	if (!check_mnt(nd->mnt))		goto unlock;	/* Refuse the same filesystem on the same mount point */	err = -EBUSY;	if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry)		goto unlock;	mnt->mnt_flags = mnt_flags;	err = graft_tree(mnt, nd);unlock:	up(&mount_sem);	mntput(mnt);out:	return err;}static int copy_mount_options (const void *data, unsigned long *where){	int i;	unsigned long page;	unsigned long size;		*where = 0;	if (!data)		return 0;	if (!(page = __get_free_page(GFP_KERNEL)))		return -ENOMEM;	/* We only care that *some* data at the address the user	 * gave us is valid.  Just in case, we'll zero	 * the remainder of the page.	 */	/* copy_from_user cannot cross TASK_SIZE ! */	size = TASK_SIZE - (unsigned long)data;	if (size > PAGE_SIZE)		size = PAGE_SIZE;	i = size - copy_from_user((void *)page, data, size);	if (!i) {		free_page(page); 		return -EFAULT;	}	if (i != PAGE_SIZE)		memset((char *)page + i, 0, PAGE_SIZE - i);	*where = page;	return 0;}/* * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * Pre-0.97 versions of mount() didn't have a flags word. * When the flags word was introduced its top half was required * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. * Therefore, if this magic number is present, it carries no information * and must be discarded. */long do_mount(char * dev_name, char * dir_name, char *type_page,		  unsigned long flags, void *data_page){	struct nameidata nd;	int retval = 0;	int mnt_flags = 0;	/* Discard magic */	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)		flags &= ~MS_MGC_MSK;	/* Basic sanity checks */	if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))		return -EINVAL;	if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))		return -EINVAL;	/* Separate the per-mountpoint flags */	if (flags & MS_NOSUID)		mnt_flags |= MNT_NOSUID;	if (flags & MS_NODEV)		mnt_flags |= MNT_NODEV;	if (flags & MS_NOEXEC)		mnt_flags |= MNT_NOEXEC;	flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);	/* ... and get the mountpoint */	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))		retval = path_walk(dir_name, &nd);	if (retval)		return retval;	if (flags & MS_REMOUNT)		retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,				    data_page);	else if (flags & MS_BIND)		retval = do_loopback(&nd, dev_name, flags & MS_REC);	else if (flags & MS_MOVE)		retval = do_move_mount(&nd, dev_name);	else		retval = do_add_mount(&nd, type_page, flags, mnt_flags,				      dev_name, data_page);	path_release(&nd);	return retval;}asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,			  unsigned long flags, void * data){	int retval;	unsigned long data_page;	unsigned long type_page;	unsigned long dev_page;	char *dir_page;	retval = copy_mount_options (type, &type_page);	if (retval < 0)		return retval;	dir_page = getname(dir_name);	retval = PTR_ERR(dir_page);	if (IS_ERR(dir_page))		goto out1;	retval = copy_mount_options (dev_name, &dev_page);	if (retval < 0)		goto out2;	retval = copy_mount_options (data, &data_page);	if (retval < 0)		goto out3;	lock_kernel();	retval = do_mount((char*)dev_page, dir_page, (char*)type_page,			  flags, (void*)data_page);	unlock_kernel();	free_page(data_page);out3:	free_page(dev_page);out2:	putname(dir_page);out1:	free_page(type_page);	return retval;}static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd){	struct task_struct *p;	struct fs_struct *fs;	read_lock(&tasklist_lock);	for_each_task(p) {		task_lock(p);		fs = p->fs;		if (fs) {			atomic_inc(&fs->count);			task_unlock(p);			if (fs->root==old_nd->dentry&&fs->rootmnt==old_nd->mnt)				set_fs_root(fs, new_nd->mnt, new_nd->dentry);			if (fs->pwd==old_nd->dentry&&fs->pwdmnt==old_nd->mnt)				set_fs_pwd(fs, new_nd->mnt, new_nd->dentry);			put_fs_struct(fs);		} else			task_unlock(p);	}	read_unlock(&tasklist_lock);}/* * Moves the current root to put_root, and sets root/cwd of all processes * which had them on the old root to new_root. * * Note: *  - we don't move root/cwd if they are not at the root (reason: if something *    cared enough to change them, it's probably wrong to force them elsewhere) *  - it's okay to pick a root that isn't the root of a file system, e.g. *    /nfs/my_root where /nfs is the mount point. It must be a mountpoint, *    though, so you may need to say mount --bind /nfs/my_root /nfs/my_root *    first. */asmlinkage long sys_pivot_root(const char *new_root, const char *put_old){	struct vfsmount *tmp;	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;	char *name;	int error;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	lock_kernel();	name = getname(new_root);	error = PTR_ERR(name);	if (IS_ERR(name))		goto out0;	error = 0;	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))		error = path_walk(name, &new_nd);	putname(name);	if (error)		goto out0;	error = -EINVAL;	if (!check_mnt(new_nd.mnt))		goto out1;	name = getname(put_old);	error = PTR_ERR(name);	if (IS_ERR(name))		goto out1;	error = 0;	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))		error = path_walk(name, &old_nd);	putname(name);	if (error)		goto out1;	read_lock(&current->fs->lock);	user_nd.mnt = mntget(current->fs->rootmnt);	user_nd.dentry = dget(current->fs->root);	read_unlock(&current->fs->lock);	down(&mount_sem);	down(&old_nd.dentry->d_inode->i_zombie);	error = -EINVAL;	if (!check_mnt(user_nd.mnt))		goto out2;	error = -ENOENT;	if (IS_DEADDIR(new_nd.dentry->d_inode))		goto out2;	if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))		goto out2;	if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))		goto out2;	error = -EBUSY;	if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt)		goto out2; /* loop */	error = -EINVAL;	if (user_nd.mnt->mnt_root != user_nd.dentry)		goto out2;	if (new_nd.mnt->mnt_root != new_nd.dentry)		goto out2; /* not a mountpoint */	tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */	spin_lock(&dcache_lock);	if (tmp != new_nd.mnt) {		for (;;) {			if (tmp->mnt_parent == tmp)				goto out3;			if (tmp->mnt_parent == new_nd.mnt)				break;			tmp = tmp->mnt_parent;		}		if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry))			goto out3;	} else if (!is_subdir(old_nd.dentry, new_nd.dentry))		goto out3;	detach_mnt(new_nd.mnt, &parent_nd);	detach_mnt(user_nd.mnt, &root_parent);	attach_mnt(user_nd.mnt, &old_nd);	attach_mnt(new_nd.mnt, &root_parent);	spin_unlock(&dcache_lock);	chroot_fs_refs(&user_nd, &new_nd);	error = 0;	path_release(&root_parent);	path_release(&parent_nd);out2:	up(&old_nd.dentry->d_inode->i_zombie);	up(&mount_sem);	path_release(&user_nd);	path_release(&old_nd);out1:	path_release(&new_nd);out0:	unlock_kernel();	return error;out3:	spin_unlock(&dcache_lock);	goto out2;}/* * Absolutely minimal fake fs - only empty root directory and nothing else. * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just * something to go with root vfsmount. */static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry){	d_add(dentry, NULL);	return NULL;}static struct file_operations rootfs_dir_operations = {	read:		generic_read_dir,	readdir:	dcache_readdir,};static struct inode_operations rootfs_dir_inode_operations = {	lookup:		rootfs_lookup,};static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent){	struct inode * inode;	struct dentry * root;	static struct super_operations s_ops = {};	sb->s_op = &s_ops;	inode = new_inode(sb);	if (!inode)		return NULL;	inode->i_mode = S_IFDIR|0555;	inode->i_uid = inode->i_gid = 0;	inode->i_op = &rootfs_dir_inode_operations;	inode->i_fop = &rootfs_dir_operations;	root = d_alloc_root(inode);	if (!root) {		iput(inode);		return NULL;	}	sb->s_root = root;	return sb;}static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT);static void __init init_mount_tree(void){	register_filesystem(&root_fs_type);	root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL);	if (IS_ERR(root_vfsmnt))		panic("can't allocate root vfsmount");}void __init mnt_init(unsigned long mempages){	struct list_head *d;	unsigned long order;	unsigned int nr_hash;	int i;	mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),					0, SLAB_HWCACHE_ALIGN, NULL, NULL);	if (!mnt_cache)		panic("Cannot create vfsmount cache");	mempages >>= (16 - PAGE_SHIFT);	mempages *= sizeof(struct list_head);	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)		;	do {		mount_hashtable = (struct list_head *)			__get_free_pages(GFP_ATOMIC, order);	} while (mount_hashtable == NULL && --order >= 0);	if (!mount_hashtable)		panic("Failed to allocate mount hash table\n");	/*	 * Find the power-of-two list-heads that can fit into the allocation..	 * We don't guarantee that "sizeof(struct list_head)" is necessarily	 * a power-of-two.	 */	nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct list_head);	hash_bits = 0;	do {		hash_bits++;	} while ((nr_hash >> hash_bits) != 0);	hash_bits--;	/*	 * Re-calculate the actual number of entries and the mask	 * from the number of bits we can fit.	 */	nr_hash = 1UL << hash_bits;	hash_mask = nr_hash-1;	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",			nr_hash, order, (PAGE_SIZE << order));	/* And initialize the newly allocated array */	d = mount_hashtable;	i = nr_hash;	do {		INIT_LIST_HEAD(d);		d++;		i--;	} while (i);	init_mount_tree();}#ifdef CONFIG_BLK_DEV_INITRDint __init change_root(kdev_t new_root_dev,const char *put_old){	struct vfsmount *old_rootmnt;	struct nameidata devfs_nd, nd;	struct nameidata parent_nd;	char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL);	int error = 0;	if (new_devname)		strcpy(new_devname, "/dev/root.old");	read_lock(&current->fs->lock);	old_rootmnt = mntget(current->fs->rootmnt);	read_unlock(&current->fs->lock);	/*  First unmount devfs if mounted  */	if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))		error = path_walk("/dev", &devfs_nd);	if (!error) {		if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC &&		    devfs_nd.dentry == devfs_nd.mnt->mnt_root) {			do_umount(devfs_nd.mnt, 0);		}		path_release(&devfs_nd);	}	spin_lock(&dcache_lock);	detach_mnt(old_rootmnt, &parent_nd);	spin_unlock(&dcache_lock);	ROOT_DEV = new_root_dev;	mount_root();#if 1	shrink_dcache();	printk("change_root: old root has d_count=%d\n", 	       atomic_read(&old_rootmnt->mnt_root->d_count));#endif	mount_devfs_fs ();	/*	 * Get the new mount directory	 */	error = 0;	if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))		error = path_walk(put_old, &nd);	if (error) {		int blivet;		struct block_device *ramdisk = old_rootmnt->mnt_sb->s_bdev;		atomic_inc(&ramdisk->bd_count);		blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS);		printk(KERN_NOTICE "Trying to unmount old root ... ");		if (!blivet) {			spin_lock(&dcache_lock);			list_del_init(&old_rootmnt->mnt_list); 			spin_unlock(&dcache_lock); 			mntput(old_rootmnt);			mntput(old_rootmnt);			blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0);			path_release(&parent_nd);			blkdev_put(ramdisk, BDEV_FS);		}		if (blivet) {			printk(KERN_ERR "error %d\n", blivet);		} else {			printk("okay\n");			error = 0;		}					kfree(new_devname);		return error;	}	spin_lock(&dcache_lock);	attach_mnt(old_rootmnt, &nd);	if (new_devname) {		if (old_rootmnt->mnt_devname)			kfree(old_rootmnt->mnt_devname);		old_rootmnt->mnt_devname = new_devname;	}	spin_unlock(&dcache_lock);	/* put the old stuff */	path_release(&parent_nd);	mntput(old_rootmnt);	path_release(&nd);	return 0;}#endif

⌨️ 快捷键说明

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