diff options
Diffstat (limited to 'fs/proc/generic.c')
| -rw-r--r-- | fs/proc/generic.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 43e54e86cefd..4fb81e9c94e3 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -300,10 +300,10 @@ out: | |||
| 300 | return rtn; | 300 | return rtn; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | static DEFINE_IDR(proc_inum_idr); | 303 | static DEFINE_IDA(proc_inum_ida); |
| 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ |
| 305 | 305 | ||
| 306 | #define PROC_DYNAMIC_FIRST 0xF0000000UL | 306 | #define PROC_DYNAMIC_FIRST 0xF0000000U |
| 307 | 307 | ||
| 308 | /* | 308 | /* |
| 309 | * Return an inode number between PROC_DYNAMIC_FIRST and | 309 | * Return an inode number between PROC_DYNAMIC_FIRST and |
| @@ -311,36 +311,33 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | |||
| 311 | */ | 311 | */ |
| 312 | static unsigned int get_inode_number(void) | 312 | static unsigned int get_inode_number(void) |
| 313 | { | 313 | { |
| 314 | int i, inum = 0; | 314 | unsigned int i; |
| 315 | int error; | 315 | int error; |
| 316 | 316 | ||
| 317 | retry: | 317 | retry: |
| 318 | if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0) | 318 | if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0) |
| 319 | return 0; | 319 | return 0; |
| 320 | 320 | ||
| 321 | spin_lock(&proc_inum_lock); | 321 | spin_lock(&proc_inum_lock); |
| 322 | error = idr_get_new(&proc_inum_idr, NULL, &i); | 322 | error = ida_get_new(&proc_inum_ida, &i); |
| 323 | spin_unlock(&proc_inum_lock); | 323 | spin_unlock(&proc_inum_lock); |
| 324 | if (error == -EAGAIN) | 324 | if (error == -EAGAIN) |
| 325 | goto retry; | 325 | goto retry; |
| 326 | else if (error) | 326 | else if (error) |
| 327 | return 0; | 327 | return 0; |
| 328 | 328 | ||
| 329 | inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST; | 329 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
| 330 | 330 | spin_lock(&proc_inum_lock); | |
| 331 | /* inum will never be more than 0xf0ffffff, so no check | 331 | ida_remove(&proc_inum_ida, i); |
| 332 | * for overflow. | 332 | spin_unlock(&proc_inum_lock); |
| 333 | */ | 333 | } |
| 334 | 334 | return PROC_DYNAMIC_FIRST + i; | |
| 335 | return inum; | ||
| 336 | } | 335 | } |
| 337 | 336 | ||
| 338 | static void release_inode_number(unsigned int inum) | 337 | static void release_inode_number(unsigned int inum) |
| 339 | { | 338 | { |
| 340 | int id = (inum - PROC_DYNAMIC_FIRST) | ~MAX_ID_MASK; | ||
| 341 | |||
| 342 | spin_lock(&proc_inum_lock); | 339 | spin_lock(&proc_inum_lock); |
| 343 | idr_remove(&proc_inum_idr, id); | 340 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
| 344 | spin_unlock(&proc_inum_lock); | 341 | spin_unlock(&proc_inum_lock); |
| 345 | } | 342 | } |
| 346 | 343 | ||
| @@ -597,6 +594,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
| 597 | ent->pde_users = 0; | 594 | ent->pde_users = 0; |
| 598 | spin_lock_init(&ent->pde_unload_lock); | 595 | spin_lock_init(&ent->pde_unload_lock); |
| 599 | ent->pde_unload_completion = NULL; | 596 | ent->pde_unload_completion = NULL; |
| 597 | INIT_LIST_HEAD(&ent->pde_openers); | ||
| 600 | out: | 598 | out: |
| 601 | return ent; | 599 | return ent; |
| 602 | } | 600 | } |
| @@ -789,15 +787,25 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
| 789 | spin_unlock(&de->pde_unload_lock); | 787 | spin_unlock(&de->pde_unload_lock); |
| 790 | 788 | ||
| 791 | continue_removing: | 789 | continue_removing: |
| 790 | spin_lock(&de->pde_unload_lock); | ||
| 791 | while (!list_empty(&de->pde_openers)) { | ||
| 792 | struct pde_opener *pdeo; | ||
| 793 | |||
| 794 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | ||
| 795 | list_del(&pdeo->lh); | ||
| 796 | spin_unlock(&de->pde_unload_lock); | ||
| 797 | pdeo->release(pdeo->inode, pdeo->file); | ||
| 798 | kfree(pdeo); | ||
| 799 | spin_lock(&de->pde_unload_lock); | ||
| 800 | } | ||
| 801 | spin_unlock(&de->pde_unload_lock); | ||
| 802 | |||
| 792 | if (S_ISDIR(de->mode)) | 803 | if (S_ISDIR(de->mode)) |
| 793 | parent->nlink--; | 804 | parent->nlink--; |
| 794 | de->nlink = 0; | 805 | de->nlink = 0; |
| 795 | if (de->subdir) { | 806 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " |
| 796 | printk(KERN_WARNING "%s: removing non-empty directory " | ||
| 797 | "'%s/%s', leaking at least '%s'\n", __func__, | 807 | "'%s/%s', leaking at least '%s'\n", __func__, |
| 798 | de->parent->name, de->name, de->subdir->name); | 808 | de->parent->name, de->name, de->subdir->name); |
| 799 | WARN_ON(1); | ||
| 800 | } | ||
| 801 | if (atomic_dec_and_test(&de->count)) | 809 | if (atomic_dec_and_test(&de->count)) |
| 802 | free_proc_entry(de); | 810 | free_proc_entry(de); |
| 803 | } | 811 | } |
