aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c34
-rw-r--r--include/linux/mount.h1
2 files changed, 35 insertions, 0 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 1bf302d0478b..8ca6317cb401 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -27,6 +27,7 @@
27#include <linux/mount.h> 27#include <linux/mount.h>
28#include <linux/ramfs.h> 28#include <linux/ramfs.h>
29#include <linux/log2.h> 29#include <linux/log2.h>
30#include <linux/idr.h>
30#include <asm/uaccess.h> 31#include <asm/uaccess.h>
31#include <asm/unistd.h> 32#include <asm/unistd.h>
32#include "pnode.h" 33#include "pnode.h"
@@ -39,6 +40,7 @@
39__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); 40__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
40 41
41static int event; 42static int event;
43static DEFINE_IDA(mnt_id_ida);
42 44
43static struct list_head *mount_hashtable __read_mostly; 45static struct list_head *mount_hashtable __read_mostly;
44static struct kmem_cache *mnt_cache __read_mostly; 46static struct kmem_cache *mnt_cache __read_mostly;
@@ -58,10 +60,41 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
58 60
59#define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) 61#define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
60 62
63/* allocation is serialized by namespace_sem */
64static int mnt_alloc_id(struct vfsmount *mnt)
65{
66 int res;
67
68retry:
69 ida_pre_get(&mnt_id_ida, GFP_KERNEL);
70 spin_lock(&vfsmount_lock);
71 res = ida_get_new(&mnt_id_ida, &mnt->mnt_id);
72 spin_unlock(&vfsmount_lock);
73 if (res == -EAGAIN)
74 goto retry;
75
76 return res;
77}
78
79static void mnt_free_id(struct vfsmount *mnt)
80{
81 spin_lock(&vfsmount_lock);
82 ida_remove(&mnt_id_ida, mnt->mnt_id);
83 spin_unlock(&vfsmount_lock);
84}
85
61struct vfsmount *alloc_vfsmnt(const char *name) 86struct vfsmount *alloc_vfsmnt(const char *name)
62{ 87{
63 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); 88 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
64 if (mnt) { 89 if (mnt) {
90 int err;
91
92 err = mnt_alloc_id(mnt);
93 if (err) {
94 kmem_cache_free(mnt_cache, mnt);
95 return NULL;
96 }
97
65 atomic_set(&mnt->mnt_count, 1); 98 atomic_set(&mnt->mnt_count, 1);
66 INIT_LIST_HEAD(&mnt->mnt_hash); 99 INIT_LIST_HEAD(&mnt->mnt_hash);
67 INIT_LIST_HEAD(&mnt->mnt_child); 100 INIT_LIST_HEAD(&mnt->mnt_child);
@@ -353,6 +386,7 @@ EXPORT_SYMBOL(simple_set_mnt);
353void free_vfsmnt(struct vfsmount *mnt) 386void free_vfsmnt(struct vfsmount *mnt)
354{ 387{
355 kfree(mnt->mnt_devname); 388 kfree(mnt->mnt_devname);
389 mnt_free_id(mnt);
356 kmem_cache_free(mnt_cache, mnt); 390 kmem_cache_free(mnt_cache, mnt);
357} 391}
358 392
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 87b24cea1863..f0dfb17ffccc 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -56,6 +56,7 @@ struct vfsmount {
56 struct list_head mnt_slave; /* slave list entry */ 56 struct list_head mnt_slave; /* slave list entry */
57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ 57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
58 struct mnt_namespace *mnt_ns; /* containing namespace */ 58 struct mnt_namespace *mnt_ns; /* containing namespace */
59 int mnt_id; /* mount identifier */
59 /* 60 /*
60 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 61 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
61 * to let these frequently modified fields in a separate cache line 62 * to let these frequently modified fields in a separate cache line