2637 lines · 63.3 KB · C
RawDownload
/* *  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/syscalls.h>#include <linux/export.h>#include <linux/capability.h>#include <linux/mnt_namespace.h>#include <linux/namei.h>#include <linux/security.h>#include <linux/idr.h>#include <linux/acct.h>		/* acct_auto_close_mnt */#include <linux/ramfs.h>	/* init_rootfs */#include <linux/fs_struct.h>	/* get_fs_root et.al. */#include <linux/fsnotify.h>	/* fsnotify_vfsmount_delete */#include <linux/uaccess.h>#include "pnode.h"#include "internal.h" #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))#define HASH_SIZE (1UL << HASH_SHIFT) static int event;static DEFINE_IDA(mnt_id_ida);static DEFINE_IDA(mnt_group_ida);static DEFINE_SPINLOCK(mnt_id_lock);static int mnt_id_start = 0;static int mnt_group_start = 1; static struct list_head *mount_hashtable __read_mostly;static struct kmem_cache *mnt_cache __read_mostly;static struct rw_semaphore namespace_sem; /* /sys/fs */struct kobject *fs_kobj;EXPORT_SYMBOL_GPL(fs_kobj); /* * vfsmount lock may be taken for read to prevent changes to the * vfsmount hash, ie. during mountpoint lookups or walking back * up the tree. * * It should be taken for write in all cases where the vfsmount * tree or hash is modified or when a vfsmount structure is modified. */DEFINE_BRLOCK(vfsmount_lock); 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_SHIFT);	return tmp & (HASH_SIZE - 1);} #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) /* * allocation is serialized by namespace_sem, but we need the spinlock to * serialize with freeing. */static int mnt_alloc_id(struct mount *mnt){	int res; retry:	ida_pre_get(&mnt_id_ida, GFP_KERNEL);	spin_lock(&mnt_id_lock);	res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);	if (!res)		mnt_id_start = mnt->mnt_id + 1;	spin_unlock(&mnt_id_lock);	if (res == -EAGAIN)		goto retry; 	return res;} static void mnt_free_id(struct mount *mnt){	int id = mnt->mnt_id;	spin_lock(&mnt_id_lock);	ida_remove(&mnt_id_ida, id);	if (mnt_id_start > id)		mnt_id_start = id;	spin_unlock(&mnt_id_lock);} /* * Allocate a new peer group ID * * mnt_group_ida is protected by namespace_sem */static int mnt_alloc_group_id(struct mount *mnt){	int res; 	if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))		return -ENOMEM; 	res = ida_get_new_above(&mnt_group_ida,				mnt_group_start,				&mnt->mnt_group_id);	if (!res)		mnt_group_start = mnt->mnt_group_id + 1; 	return res;} /* * Release a peer group ID */void mnt_release_group_id(struct mount *mnt){	int id = mnt->mnt_group_id;	ida_remove(&mnt_group_ida, id);	if (mnt_group_start > id)		mnt_group_start = id;	mnt->mnt_group_id = 0;} /* * vfsmount lock must be held for read */static inline void mnt_add_count(struct mount *mnt, int n){#ifdef CONFIG_SMP	this_cpu_add(mnt->mnt_pcp->mnt_count, n);#else	preempt_disable();	mnt->mnt_count += n;	preempt_enable();#endif} /* * vfsmount lock must be held for write */unsigned int mnt_get_count(struct mount *mnt){#ifdef CONFIG_SMP	unsigned int count = 0;	int cpu; 	for_each_possible_cpu(cpu) {		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;	} 	return count;#else	return mnt->mnt_count;#endif} static struct mount *alloc_vfsmnt(const char *name){	struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);	if (mnt) {		int err; 		err = mnt_alloc_id(mnt);		if (err)			goto out_free_cache; 		if (name) {			mnt->mnt_devname = kstrdup(name, GFP_KERNEL);			if (!mnt->mnt_devname)				goto out_free_id;		} #ifdef CONFIG_SMP		mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);		if (!mnt->mnt_pcp)			goto out_free_devname; 		this_cpu_add(mnt->mnt_pcp->mnt_count, 1);#else		mnt->mnt_count = 1;		mnt->mnt_writers = 0;#endif 		INIT_LIST_HEAD(&mnt->mnt_hash);		INIT_LIST_HEAD(&mnt->mnt_child);		INIT_LIST_HEAD(&mnt->mnt_mounts);		INIT_LIST_HEAD(&mnt->mnt_list);		INIT_LIST_HEAD(&mnt->mnt_expire);		INIT_LIST_HEAD(&mnt->mnt_share);		INIT_LIST_HEAD(&mnt->mnt_slave_list);		INIT_LIST_HEAD(&mnt->mnt_slave);#ifdef CONFIG_FSNOTIFY		INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);#endif	}	return mnt; #ifdef CONFIG_SMPout_free_devname:	kfree(mnt->mnt_devname);#endifout_free_id:	mnt_free_id(mnt);out_free_cache:	kmem_cache_free(mnt_cache, mnt);	return NULL;} /* * Most r/o checks on a fs are for operations that take * discrete amounts of time, like a write() or unlink(). * We must keep track of when those operations start * (for permission checks) and when they end, so that * we can determine when writes are able to occur to * a filesystem. *//* * __mnt_is_readonly: check whether a mount is read-only * @mnt: the mount to check for its write status * * This shouldn't be used directly ouside of the VFS. * It does not guarantee that the filesystem will stay * r/w, just that it is right *now*.  This can not and * should not be used in place of IS_RDONLY(inode). * mnt_want/drop_write() will _keep_ the filesystem * r/w. */int __mnt_is_readonly(struct vfsmount *mnt){	if (mnt->mnt_flags & MNT_READONLY)		return 1;	if (mnt->mnt_sb->s_flags & MS_RDONLY)		return 1;	return 0;}EXPORT_SYMBOL_GPL(__mnt_is_readonly); static inline void mnt_inc_writers(struct mount *mnt){#ifdef CONFIG_SMP	this_cpu_inc(mnt->mnt_pcp->mnt_writers);#else	mnt->mnt_writers++;#endif} static inline void mnt_dec_writers(struct mount *mnt){#ifdef CONFIG_SMP	this_cpu_dec(mnt->mnt_pcp->mnt_writers);#else	mnt->mnt_writers--;#endif} static unsigned int mnt_get_writers(struct mount *mnt){#ifdef CONFIG_SMP	unsigned int count = 0;	int cpu; 	for_each_possible_cpu(cpu) {		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers;	} 	return count;#else	return mnt->mnt_writers;#endif} static int mnt_is_readonly(struct vfsmount *mnt){	if (mnt->mnt_sb->s_readonly_remount)		return 1;	/* Order wrt setting s_flags/s_readonly_remount in do_remount() */	smp_rmb();	return __mnt_is_readonly(mnt);} /* * Most r/o checks on a fs are for operations that take * discrete amounts of time, like a write() or unlink(). * We must keep track of when those operations start * (for permission checks) and when they end, so that * we can determine when writes are able to occur to * a filesystem. *//** * mnt_want_write - get write access to a mount * @m: the mount on which to take a write * * This tells the low-level filesystem that a write is * about to be performed to it, and makes sure that * writes are allowed before returning success.  When * the write operation is finished, mnt_drop_write() * must be called.  This is effectively a refcount. */int mnt_want_write(struct vfsmount *m){	struct mount *mnt = real_mount(m);	int ret = 0; 	preempt_disable();	mnt_inc_writers(mnt);	/*	 * The store to mnt_inc_writers must be visible before we pass	 * MNT_WRITE_HOLD loop below, so that the slowpath can see our	 * incremented count after it has set MNT_WRITE_HOLD.	 */	smp_mb();	while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)		cpu_relax();	/*	 * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will	 * be set to match its requirements. So we must not load that until	 * MNT_WRITE_HOLD is cleared.	 */	smp_rmb();	if (mnt_is_readonly(m)) {		mnt_dec_writers(mnt);		ret = -EROFS;	}	preempt_enable();	return ret;}EXPORT_SYMBOL_GPL(mnt_want_write); /** * mnt_clone_write - get write access to a mount * @mnt: the mount on which to take a write * * This is effectively like mnt_want_write, except * it must only be used to take an extra write reference * on a mountpoint that we already know has a write reference * on it. This allows some optimisation. * * After finished, mnt_drop_write must be called as usual to * drop the reference. */int mnt_clone_write(struct vfsmount *mnt){	/* superblock may be r/o */	if (__mnt_is_readonly(mnt))		return -EROFS;	preempt_disable();	mnt_inc_writers(real_mount(mnt));	preempt_enable();	return 0;}EXPORT_SYMBOL_GPL(mnt_clone_write); /** * mnt_want_write_file - get write access to a file's mount * @file: the file who's mount on which to take a write * * This is like mnt_want_write, but it takes a file and can * do some optimisations if the file is open for write already */int mnt_want_write_file(struct file *file){	struct inode *inode = file->f_dentry->d_inode;	if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))		return mnt_want_write(file->f_path.mnt);	else		return mnt_clone_write(file->f_path.mnt);}EXPORT_SYMBOL_GPL(mnt_want_write_file); /** * mnt_drop_write - give up write access to a mount * @mnt: the mount on which to give up write access * * Tells the low-level filesystem that we are done * performing writes to it.  Must be matched with * mnt_want_write() call above. */void mnt_drop_write(struct vfsmount *mnt){	preempt_disable();	mnt_dec_writers(real_mount(mnt));	preempt_enable();}EXPORT_SYMBOL_GPL(mnt_drop_write); void mnt_drop_write_file(struct file *file){	mnt_drop_write(file->f_path.mnt);}EXPORT_SYMBOL(mnt_drop_write_file); static int mnt_make_readonly(struct mount *mnt){	int ret = 0; 	br_write_lock(&vfsmount_lock);	mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;	/*	 * After storing MNT_WRITE_HOLD, we'll read the counters. This store	 * should be visible before we do.	 */	smp_mb(); 	/*	 * With writers on hold, if this value is zero, then there are	 * definitely no active writers (although held writers may subsequently	 * increment the count, they'll have to wait, and decrement it after	 * seeing MNT_READONLY).	 *	 * It is OK to have counter incremented on one CPU and decremented on	 * another: the sum will add up correctly. The danger would be when we	 * sum up each counter, if we read a counter before it is incremented,	 * but then read another CPU's count which it has been subsequently	 * decremented from -- we would see more decrements than we should.	 * MNT_WRITE_HOLD protects against this scenario, because	 * mnt_want_write first increments count, then smp_mb, then spins on	 * MNT_WRITE_HOLD, so it can't be decremented by another CPU while	 * we're counting up here.	 */	if (mnt_get_writers(mnt) > 0)		ret = -EBUSY;	else		mnt->mnt.mnt_flags |= MNT_READONLY;	/*	 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers	 * that become unheld will see MNT_READONLY.	 */	smp_wmb();	mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;	br_write_unlock(&vfsmount_lock);	return ret;} static void __mnt_unmake_readonly(struct mount *mnt){	br_write_lock(&vfsmount_lock);	mnt->mnt.mnt_flags &= ~MNT_READONLY;	br_write_unlock(&vfsmount_lock);} int sb_prepare_remount_readonly(struct super_block *sb){	struct mount *mnt;	int err = 0; 	/* Racy optimization.  Recheck the counter under MNT_WRITE_HOLD */	if (atomic_long_read(&sb->s_remove_count))		return -EBUSY; 	br_write_lock(&vfsmount_lock);	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {		if (!(mnt->mnt.mnt_flags & MNT_READONLY)) {			mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;			smp_mb();			if (mnt_get_writers(mnt) > 0) {				err = -EBUSY;				break;			}		}	}	if (!err && atomic_long_read(&sb->s_remove_count))		err = -EBUSY; 	if (!err) {		sb->s_readonly_remount = 1;		smp_wmb();	}	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {		if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)			mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;	}	br_write_unlock(&vfsmount_lock); 	return err;} static void free_vfsmnt(struct mount *mnt){	kfree(mnt->mnt_devname);	mnt_free_id(mnt);#ifdef CONFIG_SMP	free_percpu(mnt->mnt_pcp);#endif	kmem_cache_free(mnt_cache, mnt);} /* * find the first or last mount at @dentry on vfsmount @mnt depending on * @dir. If @dir is set return the first mount else return the last mount. * vfsmount_lock must be held for read or write. */struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,			      int dir){	struct list_head *head = mount_hashtable + hash(mnt, dentry);	struct list_head *tmp = head;

Lines 1–500 of 2637.