Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8f2b548 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs fixes from Al Viro:
 "A nasty bug in fs/namespace.c caught by Andrey + a couple of less
  serious unpleasantness - ecryptfs misc device playing hopeless games
  with try_module_get() and palinfo procfs support being...  not quite
  correctly done, to be polite."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  mnt: release locks on error path in do_loopback
  palinfo fixes
  procfs: add proc_remove_subtree()
  ecryptfs: close rmmod race
parents 43ecdb0d e9c5d8a5
Loading
Loading
Loading
Loading
+13 −64
Original line number Diff line number Diff line
@@ -849,17 +849,6 @@ static palinfo_entry_t palinfo_entries[]={

#define NR_PALINFO_ENTRIES	(int) ARRAY_SIZE(palinfo_entries)

/*
 * this array is used to keep track of the proc entries we create. This is
 * required in the module mode when we need to remove all entries. The procfs code
 * does not do recursion of deletion
 *
 * Notes:
 *	- +1 accounts for the cpuN directory entry in /proc/pal
 */
#define NR_PALINFO_PROC_ENTRIES	(NR_CPUS*(NR_PALINFO_ENTRIES+1))

static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
static struct proc_dir_entry *palinfo_dir;

/*
@@ -971,60 +960,32 @@ palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
static void __cpuinit
create_palinfo_proc_entries(unsigned int cpu)
{
#	define CPUSTR	"cpu%d"

	pal_func_cpu_u_t f;
	struct proc_dir_entry **pdir;
	struct proc_dir_entry *cpu_dir;
	int j;
	char cpustr[sizeof(CPUSTR)];


	/*
	 * we keep track of created entries in a depth-first order for
	 * cleanup purposes. Each entry is stored into palinfo_proc_entries
	 */
	sprintf(cpustr,CPUSTR, cpu);
	char cpustr[3+4+1];	/* cpu numbers are up to 4095 on itanic */
	sprintf(cpustr, "cpu%d", cpu);

	cpu_dir = proc_mkdir(cpustr, palinfo_dir);
	if (!cpu_dir)
		return;

	f.req_cpu = cpu;

	/*
	 * Compute the location to store per cpu entries
	 * We dont store the top level entry in this list, but
	 * remove it finally after removing all cpu entries.
	 */
	pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)];
	*pdir++ = cpu_dir;
	for (j=0; j < NR_PALINFO_ENTRIES; j++) {
		f.func_id = j;
		*pdir = create_proc_read_entry(
		create_proc_read_entry(
			palinfo_entries[j].name, 0, cpu_dir,
			palinfo_read_entry, (void *)f.value);
		pdir++;
	}
}

static void
remove_palinfo_proc_entries(unsigned int hcpu)
{
	int j;
	struct proc_dir_entry *cpu_dir, **pdir;

	pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)];
	cpu_dir = *pdir;
	*pdir++=NULL;
	for (j=0; j < (NR_PALINFO_ENTRIES); j++) {
		if ((*pdir)) {
			remove_proc_entry ((*pdir)->name, cpu_dir);
			*pdir ++= NULL;
		}
	}

	if (cpu_dir) {
		remove_proc_entry(cpu_dir->name, palinfo_dir);
	}
	char cpustr[3+4+1];	/* cpu numbers are up to 4095 on itanic */
	sprintf(cpustr, "cpu%d", hcpu);
	remove_proc_subtree(cpustr, palinfo_dir);
}

static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
@@ -1058,6 +1019,8 @@ palinfo_init(void)

	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
	palinfo_dir = proc_mkdir("pal", NULL);
	if (!palinfo_dir)
		return -ENOMEM;

	/* Create palinfo dirs in /proc for all online cpus */
	for_each_online_cpu(i) {
@@ -1073,22 +1036,8 @@ palinfo_init(void)
static void __exit
palinfo_exit(void)
{
	int i = 0;

	/* remove all nodes: depth first pass. Could optimize this  */
	for_each_online_cpu(i) {
		remove_palinfo_proc_entries(i);
	}

	/*
	 * Remove the top level entry finally
	 */
	remove_proc_entry(palinfo_dir->name, NULL);

	/*
	 * Unregister from cpu notifier callbacks
	 */
	unregister_hotcpu_notifier(&palinfo_cpu_notifier);
	remove_proc_subtree("pal", NULL);
}

module_init(palinfo_init);
+2 −12
Original line number Diff line number Diff line
@@ -80,13 +80,6 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
	int rc;

	mutex_lock(&ecryptfs_daemon_hash_mux);
	rc = try_module_get(THIS_MODULE);
	if (rc == 0) {
		rc = -EIO;
		printk(KERN_ERR "%s: Error attempting to increment module use "
		       "count; rc = [%d]\n", __func__, rc);
		goto out_unlock_daemon_list;
	}
	rc = ecryptfs_find_daemon_by_euid(&daemon);
	if (!rc) {
		rc = -EINVAL;
@@ -96,7 +89,7 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
	if (rc) {
		printk(KERN_ERR "%s: Error attempting to spawn daemon; "
		       "rc = [%d]\n", __func__, rc);
		goto out_module_put_unlock_daemon_list;
		goto out_unlock_daemon_list;
	}
	mutex_lock(&daemon->mux);
	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
@@ -108,9 +101,6 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
	atomic_inc(&ecryptfs_num_miscdev_opens);
out_unlock_daemon:
	mutex_unlock(&daemon->mux);
out_module_put_unlock_daemon_list:
	if (rc)
		module_put(THIS_MODULE);
out_unlock_daemon_list:
	mutex_unlock(&ecryptfs_daemon_hash_mux);
	return rc;
@@ -147,7 +137,6 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file)
		       "bug.\n", __func__, rc);
		BUG();
	}
	module_put(THIS_MODULE);
	return rc;
}

@@ -471,6 +460,7 @@ out_free:


static const struct file_operations ecryptfs_miscdev_fops = {
	.owner   = THIS_MODULE,
	.open    = ecryptfs_miscdev_open,
	.poll    = ecryptfs_miscdev_poll,
	.read    = ecryptfs_miscdev_read,
+1 −1
Original line number Diff line number Diff line
@@ -1690,7 +1690,7 @@ static int do_loopback(struct path *path, const char *old_name,

	if (IS_ERR(mnt)) {
		err = PTR_ERR(mnt);
		goto out;
		goto out2;
	}

	err = graft_tree(mnt, path);
+89 −30
Original line number Diff line number Diff line
@@ -755,37 +755,8 @@ void pde_put(struct proc_dir_entry *pde)
		free_proc_entry(pde);
}

/*
 * Remove a /proc entry and free it if it's not currently in use.
 */
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
static void entry_rundown(struct proc_dir_entry *de)
{
	struct proc_dir_entry **p;
	struct proc_dir_entry *de = NULL;
	const char *fn = name;
	unsigned int len;

	spin_lock(&proc_subdir_lock);
	if (__xlate_proc_name(name, &parent, &fn) != 0) {
		spin_unlock(&proc_subdir_lock);
		return;
	}
	len = strlen(fn);

	for (p = &parent->subdir; *p; p=&(*p)->next ) {
		if (proc_match(len, fn, *p)) {
			de = *p;
			*p = de->next;
			de->next = NULL;
			break;
		}
	}
	spin_unlock(&proc_subdir_lock);
	if (!de) {
		WARN(1, "name '%s'\n", name);
		return;
	}

	spin_lock(&de->pde_unload_lock);
	/*
	 * Stop accepting new callers into module. If you're
@@ -817,6 +788,40 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
		spin_lock(&de->pde_unload_lock);
	}
	spin_unlock(&de->pde_unload_lock);
}

/*
 * Remove a /proc entry and free it if it's not currently in use.
 */
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
	struct proc_dir_entry **p;
	struct proc_dir_entry *de = NULL;
	const char *fn = name;
	unsigned int len;

	spin_lock(&proc_subdir_lock);
	if (__xlate_proc_name(name, &parent, &fn) != 0) {
		spin_unlock(&proc_subdir_lock);
		return;
	}
	len = strlen(fn);

	for (p = &parent->subdir; *p; p=&(*p)->next ) {
		if (proc_match(len, fn, *p)) {
			de = *p;
			*p = de->next;
			de->next = NULL;
			break;
		}
	}
	spin_unlock(&proc_subdir_lock);
	if (!de) {
		WARN(1, "name '%s'\n", name);
		return;
	}

	entry_rundown(de);

	if (S_ISDIR(de->mode))
		parent->nlink--;
@@ -827,3 +832,57 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
	pde_put(de);
}
EXPORT_SYMBOL(remove_proc_entry);

int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
{
	struct proc_dir_entry **p;
	struct proc_dir_entry *root = NULL, *de, *next;
	const char *fn = name;
	unsigned int len;

	spin_lock(&proc_subdir_lock);
	if (__xlate_proc_name(name, &parent, &fn) != 0) {
		spin_unlock(&proc_subdir_lock);
		return -ENOENT;
	}
	len = strlen(fn);

	for (p = &parent->subdir; *p; p=&(*p)->next ) {
		if (proc_match(len, fn, *p)) {
			root = *p;
			*p = root->next;
			root->next = NULL;
			break;
		}
	}
	if (!root) {
		spin_unlock(&proc_subdir_lock);
		return -ENOENT;
	}
	de = root;
	while (1) {
		next = de->subdir;
		if (next) {
			de->subdir = next->next;
			next->next = NULL;
			de = next;
			continue;
		}
		spin_unlock(&proc_subdir_lock);

		entry_rundown(de);
		next = de->parent;
		if (S_ISDIR(de->mode))
			next->nlink--;
		de->nlink = 0;
		if (de == root)
			break;
		pde_put(de);

		spin_lock(&proc_subdir_lock);
		de = next;
	}
	pde_put(root);
	return 0;
}
EXPORT_SYMBOL(remove_proc_subtree);
+2 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
				const struct file_operations *proc_fops,
				void *data);
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
extern int remove_proc_subtree(const char *name, struct proc_dir_entry *parent);

struct pid_namespace;

@@ -202,6 +203,7 @@ static inline struct proc_dir_entry *proc_create_data(const char *name,
	return NULL;
}
#define remove_proc_entry(name, parent) do {} while (0)
#define remove_proc_subtree(name, parent) do {} while (0)

static inline struct proc_dir_entry *proc_symlink(const char *name,
		struct proc_dir_entry *parent,const char *dest) {return NULL;}