diff options
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 80 |
1 files changed, 29 insertions, 51 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 7b3ae3cc0ef9..4b3b3ffb52f1 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/printk.h> | ||
18 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/idr.h> | 21 | #include <linux/idr.h> |
@@ -42,7 +43,7 @@ static ssize_t | |||
42 | __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | 43 | __proc_file_read(struct file *file, char __user *buf, size_t nbytes, |
43 | loff_t *ppos) | 44 | loff_t *ppos) |
44 | { | 45 | { |
45 | struct inode * inode = file->f_path.dentry->d_inode; | 46 | struct inode * inode = file_inode(file); |
46 | char *page; | 47 | char *page; |
47 | ssize_t retval=0; | 48 | ssize_t retval=0; |
48 | int eof=0; | 49 | int eof=0; |
@@ -132,11 +133,8 @@ __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | |||
132 | } | 133 | } |
133 | 134 | ||
134 | if (start == NULL) { | 135 | if (start == NULL) { |
135 | if (n > PAGE_SIZE) { | 136 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ |
136 | printk(KERN_ERR | ||
137 | "proc_file_read: Apparent buffer overflow!\n"); | ||
138 | n = PAGE_SIZE; | 137 | n = PAGE_SIZE; |
139 | } | ||
140 | n -= *ppos; | 138 | n -= *ppos; |
141 | if (n <= 0) | 139 | if (n <= 0) |
142 | break; | 140 | break; |
@@ -144,26 +142,19 @@ __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | |||
144 | n = count; | 142 | n = count; |
145 | start = page + *ppos; | 143 | start = page + *ppos; |
146 | } else if (start < page) { | 144 | } else if (start < page) { |
147 | if (n > PAGE_SIZE) { | 145 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ |
148 | printk(KERN_ERR | ||
149 | "proc_file_read: Apparent buffer overflow!\n"); | ||
150 | n = PAGE_SIZE; | 146 | n = PAGE_SIZE; |
151 | } | ||
152 | if (n > count) { | 147 | if (n > count) { |
153 | /* | 148 | /* |
154 | * Don't reduce n because doing so might | 149 | * Don't reduce n because doing so might |
155 | * cut off part of a data block. | 150 | * cut off part of a data block. |
156 | */ | 151 | */ |
157 | printk(KERN_WARNING | 152 | pr_warn("proc_file_read: count exceeded\n"); |
158 | "proc_file_read: Read count exceeded\n"); | ||
159 | } | 153 | } |
160 | } else /* start >= page */ { | 154 | } else /* start >= page */ { |
161 | unsigned long startoff = (unsigned long)(start - page); | 155 | unsigned long startoff = (unsigned long)(start - page); |
162 | if (n > (PAGE_SIZE - startoff)) { | 156 | if (n > (PAGE_SIZE - startoff)) /* buffer overflow? */ |
163 | printk(KERN_ERR | ||
164 | "proc_file_read: Apparent buffer overflow!\n"); | ||
165 | n = PAGE_SIZE - startoff; | 157 | n = PAGE_SIZE - startoff; |
166 | } | ||
167 | if (n > count) | 158 | if (n > count) |
168 | n = count; | 159 | n = count; |
169 | } | 160 | } |
@@ -188,7 +179,7 @@ static ssize_t | |||
188 | proc_file_read(struct file *file, char __user *buf, size_t nbytes, | 179 | proc_file_read(struct file *file, char __user *buf, size_t nbytes, |
189 | loff_t *ppos) | 180 | loff_t *ppos) |
190 | { | 181 | { |
191 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | 182 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
192 | ssize_t rv = -EIO; | 183 | ssize_t rv = -EIO; |
193 | 184 | ||
194 | spin_lock(&pde->pde_unload_lock); | 185 | spin_lock(&pde->pde_unload_lock); |
@@ -209,7 +200,7 @@ static ssize_t | |||
209 | proc_file_write(struct file *file, const char __user *buffer, | 200 | proc_file_write(struct file *file, const char __user *buffer, |
210 | size_t count, loff_t *ppos) | 201 | size_t count, loff_t *ppos) |
211 | { | 202 | { |
212 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | 203 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
213 | ssize_t rv = -EIO; | 204 | ssize_t rv = -EIO; |
214 | 205 | ||
215 | if (pde->write_proc) { | 206 | if (pde->write_proc) { |
@@ -261,16 +252,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) | |||
261 | if (error) | 252 | if (error) |
262 | return error; | 253 | return error; |
263 | 254 | ||
264 | if ((iattr->ia_valid & ATTR_SIZE) && | ||
265 | iattr->ia_size != i_size_read(inode)) { | ||
266 | error = vmtruncate(inode, iattr->ia_size); | ||
267 | if (error) | ||
268 | return error; | ||
269 | } | ||
270 | |||
271 | setattr_copy(inode, iattr); | 255 | setattr_copy(inode, iattr); |
272 | mark_inode_dirty(inode); | 256 | mark_inode_dirty(inode); |
273 | 257 | ||
274 | de->uid = inode->i_uid; | 258 | de->uid = inode->i_uid; |
275 | de->gid = inode->i_gid; | 259 | de->gid = inode->i_gid; |
276 | de->mode = inode->i_mode; | 260 | de->mode = inode->i_mode; |
@@ -359,18 +343,18 @@ retry: | |||
359 | if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) | 343 | if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) |
360 | return -ENOMEM; | 344 | return -ENOMEM; |
361 | 345 | ||
362 | spin_lock(&proc_inum_lock); | 346 | spin_lock_irq(&proc_inum_lock); |
363 | error = ida_get_new(&proc_inum_ida, &i); | 347 | error = ida_get_new(&proc_inum_ida, &i); |
364 | spin_unlock(&proc_inum_lock); | 348 | spin_unlock_irq(&proc_inum_lock); |
365 | if (error == -EAGAIN) | 349 | if (error == -EAGAIN) |
366 | goto retry; | 350 | goto retry; |
367 | else if (error) | 351 | else if (error) |
368 | return error; | 352 | return error; |
369 | 353 | ||
370 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { | 354 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
371 | spin_lock(&proc_inum_lock); | 355 | spin_lock_irq(&proc_inum_lock); |
372 | ida_remove(&proc_inum_ida, i); | 356 | ida_remove(&proc_inum_ida, i); |
373 | spin_unlock(&proc_inum_lock); | 357 | spin_unlock_irq(&proc_inum_lock); |
374 | return -ENOSPC; | 358 | return -ENOSPC; |
375 | } | 359 | } |
376 | *inum = PROC_DYNAMIC_FIRST + i; | 360 | *inum = PROC_DYNAMIC_FIRST + i; |
@@ -379,9 +363,10 @@ retry: | |||
379 | 363 | ||
380 | void proc_free_inum(unsigned int inum) | 364 | void proc_free_inum(unsigned int inum) |
381 | { | 365 | { |
382 | spin_lock(&proc_inum_lock); | 366 | unsigned long flags; |
367 | spin_lock_irqsave(&proc_inum_lock, flags); | ||
383 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); | 368 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
384 | spin_unlock(&proc_inum_lock); | 369 | spin_unlock_irqrestore(&proc_inum_lock, flags); |
385 | } | 370 | } |
386 | 371 | ||
387 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) | 372 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) |
@@ -418,8 +403,7 @@ static const struct dentry_operations proc_dentry_operations = | |||
418 | struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | 403 | struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, |
419 | struct dentry *dentry) | 404 | struct dentry *dentry) |
420 | { | 405 | { |
421 | struct inode *inode = NULL; | 406 | struct inode *inode; |
422 | int error = -ENOENT; | ||
423 | 407 | ||
424 | spin_lock(&proc_subdir_lock); | 408 | spin_lock(&proc_subdir_lock); |
425 | for (de = de->subdir; de ; de = de->next) { | 409 | for (de = de->subdir; de ; de = de->next) { |
@@ -428,22 +412,16 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
428 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { | 412 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { |
429 | pde_get(de); | 413 | pde_get(de); |
430 | spin_unlock(&proc_subdir_lock); | 414 | spin_unlock(&proc_subdir_lock); |
431 | error = -ENOMEM; | ||
432 | inode = proc_get_inode(dir->i_sb, de); | 415 | inode = proc_get_inode(dir->i_sb, de); |
433 | goto out_unlock; | 416 | if (!inode) |
417 | return ERR_PTR(-ENOMEM); | ||
418 | d_set_d_op(dentry, &proc_dentry_operations); | ||
419 | d_add(dentry, inode); | ||
420 | return NULL; | ||
434 | } | 421 | } |
435 | } | 422 | } |
436 | spin_unlock(&proc_subdir_lock); | 423 | spin_unlock(&proc_subdir_lock); |
437 | out_unlock: | 424 | return ERR_PTR(-ENOENT); |
438 | |||
439 | if (inode) { | ||
440 | d_set_d_op(dentry, &proc_dentry_operations); | ||
441 | d_add(dentry, inode); | ||
442 | return NULL; | ||
443 | } | ||
444 | if (de) | ||
445 | pde_put(de); | ||
446 | return ERR_PTR(error); | ||
447 | } | 425 | } |
448 | 426 | ||
449 | struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, | 427 | struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, |
@@ -466,7 +444,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | |||
466 | { | 444 | { |
467 | unsigned int ino; | 445 | unsigned int ino; |
468 | int i; | 446 | int i; |
469 | struct inode *inode = filp->f_path.dentry->d_inode; | 447 | struct inode *inode = file_inode(filp); |
470 | int ret = 0; | 448 | int ret = 0; |
471 | 449 | ||
472 | ino = inode->i_ino; | 450 | ino = inode->i_ino; |
@@ -528,7 +506,7 @@ out: | |||
528 | 506 | ||
529 | int proc_readdir(struct file *filp, void *dirent, filldir_t filldir) | 507 | int proc_readdir(struct file *filp, void *dirent, filldir_t filldir) |
530 | { | 508 | { |
531 | struct inode *inode = filp->f_path.dentry->d_inode; | 509 | struct inode *inode = file_inode(filp); |
532 | 510 | ||
533 | return proc_readdir_de(PDE(inode), filp, dirent, filldir); | 511 | return proc_readdir_de(PDE(inode), filp, dirent, filldir); |
534 | } | 512 | } |
@@ -582,7 +560,7 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
582 | 560 | ||
583 | for (tmp = dir->subdir; tmp; tmp = tmp->next) | 561 | for (tmp = dir->subdir; tmp; tmp = tmp->next) |
584 | if (strcmp(tmp->name, dp->name) == 0) { | 562 | if (strcmp(tmp->name, dp->name) == 0) { |
585 | WARN(1, KERN_WARNING "proc_dir_entry '%s/%s' already registered\n", | 563 | WARN(1, "proc_dir_entry '%s/%s' already registered\n", |
586 | dir->name, dp->name); | 564 | dir->name, dp->name); |
587 | break; | 565 | break; |
588 | } | 566 | } |
@@ -843,9 +821,9 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
843 | if (S_ISDIR(de->mode)) | 821 | if (S_ISDIR(de->mode)) |
844 | parent->nlink--; | 822 | parent->nlink--; |
845 | de->nlink = 0; | 823 | de->nlink = 0; |
846 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " | 824 | WARN(de->subdir, "%s: removing non-empty directory " |
847 | "'%s/%s', leaking at least '%s'\n", __func__, | 825 | "'%s/%s', leaking at least '%s'\n", __func__, |
848 | de->parent->name, de->name, de->subdir->name); | 826 | de->parent->name, de->name, de->subdir->name); |
849 | pde_put(de); | 827 | pde_put(de); |
850 | } | 828 | } |
851 | EXPORT_SYMBOL(remove_proc_entry); | 829 | EXPORT_SYMBOL(remove_proc_entry); |