From fdc519457a3d4e49e3f8e22d8ea4dae79194a3d2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 18 Apr 2004 22:05:51 -0700 Subject: [PATCH] Increase number of dynamic inodes in procfs From: Nathan Lynch On some larger ppc64 configurations /proc/device-tree is exhausting procfs' dynamic (non-pid) inode range (16K). This patch makes the dynamic inode range 0xf0000000-0xffffffff and changes the inode number allocator to use the idr.c allocator for the first-fit allocations. --- fs/proc/generic.c | 73 +++++++++++++++++++++++++++++++++---------------- fs/proc/inode-alloc.txt | 5 ++-- fs/proc/inode.c | 11 +++----- include/linux/proc_fs.h | 7 ++--- 4 files changed, 58 insertions(+), 38 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 27579e55ead2..d2c88ebb1b37 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -275,24 +277,46 @@ static int xlate_proc_name(const char *name, return 0; } -static unsigned long proc_alloc_map[(PROC_NDYNAMIC + BITS_PER_LONG - 1) / BITS_PER_LONG]; +static DEFINE_IDR(proc_inum_idr); +static spinlock_t proc_inum_lock = SPIN_LOCK_UNLOCKED; /* protects the above */ -spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED; +#define PROC_DYNAMIC_FIRST 0xF0000000UL -static int make_inode_number(void) +/* + * Return an inode number between PROC_DYNAMIC_FIRST and + * 0xffffffff, or zero on failure. + */ +static unsigned int get_inode_number(void) { - int i; - spin_lock(&proc_alloc_map_lock); - i = find_first_zero_bit(proc_alloc_map, PROC_NDYNAMIC); - if (i < 0 || i >= PROC_NDYNAMIC) { - i = -1; - goto out; - } - set_bit(i, proc_alloc_map); - i += PROC_DYNAMIC_FIRST; -out: - spin_unlock(&proc_alloc_map_lock); - return i; + unsigned int i, inum = 0; + +retry: + if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0) + return 0; + + spin_lock(&proc_inum_lock); + i = idr_get_new(&proc_inum_idr, NULL); + spin_unlock(&proc_inum_lock); + + if (i == -1) + goto retry; + + inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST; + + /* inum will never be more than 0xf0ffffff, so no check + * for overflow. + */ + + return inum; +} + +static void release_inode_number(unsigned int inum) +{ + int id = (inum - PROC_DYNAMIC_FIRST) | ~MAX_ID_MASK; + + spin_lock(&proc_inum_lock); + idr_remove(&proc_inum_idr, id); + spin_unlock(&proc_inum_lock); } static int @@ -346,7 +370,8 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam if (de->namelen != dentry->d_name.len) continue; if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { - int ino = de->low_ino; + unsigned int ino = de->low_ino; + error = -EINVAL; inode = proc_get_inode(dir->i_sb, ino, de); break; @@ -452,10 +477,10 @@ static struct inode_operations proc_dir_inode_operations = { static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) { - int i; + unsigned int i; - i = make_inode_number(); - if (i < 0) + i = get_inode_number(); + if (i == 0) return -EAGAIN; dp->low_ino = i; dp->next = dir->subdir; @@ -621,11 +646,13 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, void free_proc_entry(struct proc_dir_entry *de) { - int ino = de->low_ino; + unsigned int ino = de->low_ino; - if (ino < PROC_DYNAMIC_FIRST || - ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) + if (ino < PROC_DYNAMIC_FIRST) return; + + release_inode_number(ino); + if (S_ISLNK(de->mode) && de->data) kfree(de->data); kfree(de); @@ -653,8 +680,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) de->next = NULL; if (S_ISDIR(de->mode)) parent->nlink--; - clear_bit(de->low_ino - PROC_DYNAMIC_FIRST, - proc_alloc_map); proc_kill_inodes(de); de->nlink = 0; WARN_ON(de->subdir); diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt index fbcfa4e402e2..77212f938c2c 100644 --- a/fs/proc/inode-alloc.txt +++ b/fs/proc/inode-alloc.txt @@ -4,9 +4,10 @@ Current inode allocations in the proc-fs (hex-numbers): 00000001-00000fff static entries (goners) 001 root-ino - 00001000-00001fff dynamic entries + 00001000-00001fff unused 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff - 80000000-ffffffff unused + 80000000-efffffff unused + f0000000-ffffffff dynamic entries Goal: a) once we'll split the thing into several virtual filesystems we diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 119e355298d6..2d38f02c9e4e 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -188,8 +188,8 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid) return 1; } -struct inode * proc_get_inode(struct super_block * sb, int ino, - struct proc_dir_entry * de) +struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, + struct proc_dir_entry *de) { struct inode * inode; @@ -197,11 +197,8 @@ struct inode * proc_get_inode(struct super_block * sb, int ino, * Increment the use count so the dir entry can't disappear. */ de_get(de); -#if 1 -/* shouldn't ever happen */ -if (de && de->deleted) -printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count)); -#endif + + WARN_ON(de && de->deleted); inode = iget(sb, ino); if (!inode) diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 9361a2b6856e..0b12bd800fd1 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -26,9 +26,6 @@ enum { /* Finally, the dynamically allocatable proc entries are reserved: */ -#define PROC_DYNAMIC_FIRST 4096 -#define PROC_NDYNAMIC 16384 - #define PROC_SUPER_MAGIC 0x9fa0 /* @@ -53,7 +50,7 @@ typedef int (write_proc_t)(struct file *file, const char __user *buffer, typedef int (get_info_t)(char *, char **, off_t, int); struct proc_dir_entry { - unsigned short low_ino; + unsigned int low_ino; unsigned short namelen; const char *name; mode_t mode; @@ -102,7 +99,7 @@ extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); extern struct vfsmount *proc_mnt; extern int proc_fill_super(struct super_block *,void *,int); -extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *); +extern struct inode *proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *); extern int proc_match(int, const char *,struct proc_dir_entry *); -- cgit v1.2.3