Commit fdc51945 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Increase number of dynamic inodes in procfs

From: Nathan Lynch <nathanl@austin.ibm.com>

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.
parent 178036e3
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/idr.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
...@@ -275,24 +277,46 @@ static int xlate_proc_name(const char *name, ...@@ -275,24 +277,46 @@ static int xlate_proc_name(const char *name,
return 0; 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; unsigned int i, inum = 0;
spin_lock(&proc_alloc_map_lock);
i = find_first_zero_bit(proc_alloc_map, PROC_NDYNAMIC); retry:
if (i < 0 || i >= PROC_NDYNAMIC) { if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0)
i = -1; return 0;
goto out;
} spin_lock(&proc_inum_lock);
set_bit(i, proc_alloc_map); i = idr_get_new(&proc_inum_idr, NULL);
i += PROC_DYNAMIC_FIRST; spin_unlock(&proc_inum_lock);
out:
spin_unlock(&proc_alloc_map_lock); if (i == -1)
return i; 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 static int
...@@ -346,7 +370,8 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam ...@@ -346,7 +370,8 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
if (de->namelen != dentry->d_name.len) if (de->namelen != dentry->d_name.len)
continue; continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
int ino = de->low_ino; unsigned int ino = de->low_ino;
error = -EINVAL; error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de); inode = proc_get_inode(dir->i_sb, ino, de);
break; break;
...@@ -452,10 +477,10 @@ static struct inode_operations proc_dir_inode_operations = { ...@@ -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) static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{ {
int i; unsigned int i;
i = make_inode_number(); i = get_inode_number();
if (i < 0) if (i == 0)
return -EAGAIN; return -EAGAIN;
dp->low_ino = i; dp->low_ino = i;
dp->next = dir->subdir; dp->next = dir->subdir;
...@@ -621,11 +646,13 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, ...@@ -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) 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 || if (ino < PROC_DYNAMIC_FIRST)
ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
return; return;
release_inode_number(ino);
if (S_ISLNK(de->mode) && de->data) if (S_ISLNK(de->mode) && de->data)
kfree(de->data); kfree(de->data);
kfree(de); kfree(de);
...@@ -653,8 +680,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ...@@ -653,8 +680,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
de->next = NULL; de->next = NULL;
if (S_ISDIR(de->mode)) if (S_ISDIR(de->mode))
parent->nlink--; parent->nlink--;
clear_bit(de->low_ino - PROC_DYNAMIC_FIRST,
proc_alloc_map);
proc_kill_inodes(de); proc_kill_inodes(de);
de->nlink = 0; de->nlink = 0;
WARN_ON(de->subdir); WARN_ON(de->subdir);
......
...@@ -4,9 +4,10 @@ Current inode allocations in the proc-fs (hex-numbers): ...@@ -4,9 +4,10 @@ Current inode allocations in the proc-fs (hex-numbers):
00000001-00000fff static entries (goners) 00000001-00000fff static entries (goners)
001 root-ino 001 root-ino
00001000-00001fff dynamic entries 00001000-00001fff unused
0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
80000000-ffffffff unused 80000000-efffffff unused
f0000000-ffffffff dynamic entries
Goal: Goal:
a) once we'll split the thing into several virtual filesystems we a) once we'll split the thing into several virtual filesystems we
......
...@@ -188,8 +188,8 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid) ...@@ -188,8 +188,8 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1; return 1;
} }
struct inode * proc_get_inode(struct super_block * sb, int ino, struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
struct proc_dir_entry * de) struct proc_dir_entry *de)
{ {
struct inode * inode; struct inode * inode;
...@@ -197,11 +197,8 @@ struct inode * proc_get_inode(struct super_block * sb, int ino, ...@@ -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. * Increment the use count so the dir entry can't disappear.
*/ */
de_get(de); de_get(de);
#if 1
/* shouldn't ever happen */ WARN_ON(de && de->deleted);
if (de && de->deleted)
printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count));
#endif
inode = iget(sb, ino); inode = iget(sb, ino);
if (!inode) if (!inode)
......
...@@ -26,9 +26,6 @@ enum { ...@@ -26,9 +26,6 @@ enum {
/* Finally, the dynamically allocatable proc entries are reserved: */ /* Finally, the dynamically allocatable proc entries are reserved: */
#define PROC_DYNAMIC_FIRST 4096
#define PROC_NDYNAMIC 16384
#define PROC_SUPER_MAGIC 0x9fa0 #define PROC_SUPER_MAGIC 0x9fa0
/* /*
...@@ -53,7 +50,7 @@ typedef int (write_proc_t)(struct file *file, const char __user *buffer, ...@@ -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); typedef int (get_info_t)(char *, char **, off_t, int);
struct proc_dir_entry { struct proc_dir_entry {
unsigned short low_ino; unsigned int low_ino;
unsigned short namelen; unsigned short namelen;
const char *name; const char *name;
mode_t mode; mode_t mode;
...@@ -102,7 +99,7 @@ extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); ...@@ -102,7 +99,7 @@ extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
extern struct vfsmount *proc_mnt; extern struct vfsmount *proc_mnt;
extern int proc_fill_super(struct super_block *,void *,int); 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 *); extern int proc_match(int, const char *,struct proc_dir_entry *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment