History

proc: faster open/read/close with "permanent" files

Now that "struct proc_ops" exist we can start putting there stuff which could not fly with VFS "struct file_operations"... Most of fs/proc/inode.c file is dedicated to make open/read/.../close reliable in the event of disappearing /proc entries which usually happens if module is getting removed. Files like /proc/cpuinfo which never disappear simply do not need such protection. Save 2 atomic ops, 1 allocation, 1 free per open/read/close sequence for such "permanent" files. Enable "permanent" flag for /proc/cpuinfo /proc/kmsg /proc/modules /proc/slabinfo /proc/stat /proc/sysvipc/* /proc/swaps More will come once I figure out foolproof way to prevent out module authors from marking their stuff "permanent" for performance reasons when it is not. This should help with scalability: benchmark is "read /proc/cpuinfo R times by N threads scattered over the system". N R t, s (before) t, s (after) ----------------------------------------------------- 64 4096 1.582458 1.530502 -3.2% 256 4096 6.371926 6.125168 -3.9% 1024 4096 25.64888 24.47528 -4.6% Benchmark source: #include <chrono> #include <iostream> #include <thread> #include <vector> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> const int NR_CPUS = sysconf(_SC_NPROCESSORS_ONLN); int N; const char *filename; int R; int xxx = 0; int glue(int n) { cpu_set_t m; CPU_ZERO(&m); CPU_SET(n, &m); return sched_setaffinity(0, sizeof(cpu_set_t), &m); } void f(int n) { glue(n % NR_CPUS); while (*(volatile int *)&xxx == 0) { } for (int i = 0; i < R; i++) { int fd = open(filename, O_RDONLY); char buf[4096]; ssize_t rv = read(fd, buf, sizeof(buf)); asm volatile ("" :: "g" (rv)); close(fd); } } int main(int argc, char *argv[]) { if (argc < 4) { std::cerr << "usage: " << argv[0] << ' ' << "N /proc/filename R "; return 1; } N = atoi(argv[1]); filename = argv[2]; R = atoi(argv[3]); for (int i = 0; i < NR_CPUS; i++) { if (glue(i) == 0) break; } std::vector<std::thread> T; T.reserve(N); for (int i = 0; i < N; i++) { T.emplace_back(f, i); } auto t0 = std::chrono::system_clock::now(); { *(volatile int *)&xxx = 1; for (auto& t: T) { t.join(); } } auto t1 = std::chrono::system_clock::now(); std::chrono::duration<double> dt = t1 - t0; std::cout << dt.count() << ' '; return 0; } P.S.: Explicit randomization marker is added because adding non-function pointer will silently disable structure layout randomization. [akpm@linux-foundation.org: coding style fixes] Reported-by: kbuild test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Joe Perches <joe@perches.com> Link: http://lkml.kernel.org/r/20200222201539.GA22576@avx2 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Alexey Dobriyan committed 6 years ago

Commit d919b331 parent 904f39411 files · +194 −54Browse files

Unified · Split

11 files
  1. fs/proc/cpuinfo.c +1 −0
  2. fs/proc/generic.c +28 −3
  3. fs/proc/inode.c +137 −50
  4. fs/proc/internal.h +6 −0
  5. fs/proc/kmsg.c +1 −0
  6. fs/proc/stat.c +1 −0
  7. include/linux/proc_fs.h +16 −1
  8. ipc/util.c +1 −0
  9. kernel/module.c +1 −0
  10. mm/slab_common.c +1 −0
  11. mm/swapfile.c +1 −0
fs/proc/cpuinfo.c+1−0
@@ -17,6 +17,7 @@ static int cpuinfo_open(struct inode *inode, struct file *file) · 16 unmodified lines
17}17}
18 18
19static const struct proc_ops cpuinfo_proc_ops = {19static const struct proc_ops cpuinfo_proc_ops = {
20 .proc_flags = PROC_ENTRY_PERMANENT,
20 .proc_open = cpuinfo_open,21 .proc_open = cpuinfo_open,
21 .proc_read = seq_read,22 .proc_read = seq_read,
22 .proc_lseek = seq_lseek,23 .proc_lseek = seq_lseek,
fs/proc/generic.c+28−3
@@ -531,6 +531,12 @@ struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, · 530 unmodified lines
531 return p;531 return p;
532}532}
533 533
534static inline void pde_set_flags(struct proc_dir_entry *pde)
535{
536 if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT)
537 pde->flags |= PROC_ENTRY_PERMANENT;
538}
539
534struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,540struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
535 struct proc_dir_entry *parent,541 struct proc_dir_entry *parent,
536 const struct proc_ops *proc_ops, void *data)542 const struct proc_ops *proc_ops, void *data)
@@ -541,6 +547,7 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, · 4 unmodified lines
541 if (!p)547 if (!p)
542 return NULL;548 return NULL;
543 p->proc_ops = proc_ops;549 p->proc_ops = proc_ops;
550 pde_set_flags(p);
544 return proc_register(parent, p);551 return proc_register(parent, p);
545}552}
546EXPORT_SYMBOL(proc_create_data);553EXPORT_SYMBOL(proc_create_data);
@@ -572,6 +579,7 @@ static int proc_seq_release(struct inode *inode, struct file *file) · 25 unmodified lines
572}579}
573 580
574static const struct proc_ops proc_seq_ops = {581static const struct proc_ops proc_seq_ops = {
582 /* not permanent -- can call into arbitrary seq_operations */
575 .proc_open = proc_seq_open,583 .proc_open = proc_seq_open,
576 .proc_read = seq_read,584 .proc_read = seq_read,
577 .proc_lseek = seq_lseek,585 .proc_lseek = seq_lseek,
@@ -602,6 +610,7 @@ static int proc_single_open(struct inode *inode, struct file *file) · 24 unmodified lines
602}610}
603 611
604static const struct proc_ops proc_single_ops = {612static const struct proc_ops proc_single_ops = {
613 /* not permanent -- can call into arbitrary ->single_show */
605 .proc_open = proc_single_open,614 .proc_open = proc_single_open,
606 .proc_read = seq_read,615 .proc_read = seq_read,
607 .proc_lseek = seq_lseek,616 .proc_lseek = seq_lseek,
@@ -662,9 +671,13 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) · 54 unmodified lines
662 671
663 de = pde_subdir_find(parent, fn, len);672 de = pde_subdir_find(parent, fn, len);
664 if (de) {673 if (de) {
665 rb_erase(&de->subdir_node, &parent->subdir);674 if (unlikely(pde_is_permanent(de))) {
666 if (S_ISDIR(de->mode)) {675 WARN(1, "removing permanent /proc entry '%s'", de->name);
667 parent->nlink--;676 de = NULL;
677 } else {
678 rb_erase(&de->subdir_node, &parent->subdir);
679 if (S_ISDIR(de->mode))
680 parent->nlink--;
668 }681 }
669 }682 }
670 write_unlock(&proc_subdir_lock);683 write_unlock(&proc_subdir_lock);
@@ -700,12 +713,24 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) · 29 unmodified lines
700 write_unlock(&proc_subdir_lock);713 write_unlock(&proc_subdir_lock);
701 return -ENOENT;714 return -ENOENT;
702 }715 }
716 if (unlikely(pde_is_permanent(root))) {
717 write_unlock(&proc_subdir_lock);
718 WARN(1, "removing permanent /proc entry '%s/%s'",
719 root->parent->name, root->name);
720 return -EINVAL;
721 }
703 rb_erase(&root->subdir_node, &parent->subdir);722 rb_erase(&root->subdir_node, &parent->subdir);
704 723
705 de = root;724 de = root;
706 while (1) {725 while (1) {
707 next = pde_subdir_first(de);726 next = pde_subdir_first(de);
708 if (next) {727 if (next) {
728 if (unlikely(pde_is_permanent(root))) {
729 write_unlock(&proc_subdir_lock);
730 WARN(1, "removing permanent /proc entry '%s/%s'",
731 next->parent->name, next->name);
732 return -EINVAL;
733 }
709 rb_erase(&next->subdir_node, &de->subdir);734 rb_erase(&next->subdir_node, &de->subdir);
710 de = next;735 de = next;
711 continue;736 continue;
fs/proc/inode.c+137−50
@@ -259,135 +259,204 @@ void proc_entry_rundown(struct proc_dir_entry *de) · 258 unmodified lines
259 spin_unlock(&de->pde_unload_lock);259 spin_unlock(&de->pde_unload_lock);
260}260}
261 261
262static loff_t pde_lseek(struct proc_dir_entry *pde, struct file *file, loff_t offset, int whence)
263{
264 typeof_member(struct proc_ops, proc_lseek) lseek;
265
266 lseek = pde->proc_ops->proc_lseek;
267 if (!lseek)
268 lseek = default_llseek;
269 return lseek(file, offset, whence);
270}
271
262static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)272static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
263{273{
264 struct proc_dir_entry *pde = PDE(file_inode(file));274 struct proc_dir_entry *pde = PDE(file_inode(file));
265 loff_t rv = -EINVAL;275 loff_t rv = -EINVAL;
266 if (use_pde(pde)) {
267 typeof_member(struct proc_ops, proc_lseek) lseek;
268 276
269 lseek = pde->proc_ops->proc_lseek;277 if (pde_is_permanent(pde)) {
270 if (!lseek)278 return pde_lseek(pde, file, offset, whence);
271 lseek = default_llseek;279 } else if (use_pde(pde)) {
272 rv = lseek(file, offset, whence);280 rv = pde_lseek(pde, file, offset, whence);
273 unuse_pde(pde);281 unuse_pde(pde);
274 }282 }
275 return rv;283 return rv;
276}284}
277 285
286static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __user *buf, size_t count, loff_t *ppos)
287{
288 typeof_member(struct proc_ops, proc_read) read;
289
290 read = pde->proc_ops->proc_read;
291 if (read)
292 return read(file, buf, count, ppos);
293 return -EIO;
294}
295
278static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)296static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
279{297{
280 struct proc_dir_entry *pde = PDE(file_inode(file));298 struct proc_dir_entry *pde = PDE(file_inode(file));
281 ssize_t rv = -EIO;299 ssize_t rv = -EIO;
282 if (use_pde(pde)) {
283 typeof_member(struct proc_ops, proc_read) read;
284 300
285 read = pde->proc_ops->proc_read;301 if (pde_is_permanent(pde)) {
286 if (read)302 return pde_read(pde, file, buf, count, ppos);
287 rv = read(file, buf, count, ppos);303 } else if (use_pde(pde)) {
304 rv = pde_read(pde, file, buf, count, ppos);
288 unuse_pde(pde);305 unuse_pde(pde);
289 }306 }
290 return rv;307 return rv;
291}308}
292 309
310static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos)
311{
312 typeof_member(struct proc_ops, proc_write) write;
313
314 write = pde->proc_ops->proc_write;
315 if (write)
316 return write(file, buf, count, ppos);
317 return -EIO;
318}
319
293static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)320static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
294{321{
295 struct proc_dir_entry *pde = PDE(file_inode(file));322 struct proc_dir_entry *pde = PDE(file_inode(file));
296 ssize_t rv = -EIO;323 ssize_t rv = -EIO;
297 if (use_pde(pde)) {
298 typeof_member(struct proc_ops, proc_write) write;
299 324
300 write = pde->proc_ops->proc_write;325 if (pde_is_permanent(pde)) {
301 if (write)326 return pde_write(pde, file, buf, count, ppos);
302 rv = write(file, buf, count, ppos);327 } else if (use_pde(pde)) {
328 rv = pde_write(pde, file, buf, count, ppos);
303 unuse_pde(pde);329 unuse_pde(pde);
304 }330 }
305 return rv;331 return rv;
306}332}
307 333
334static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts)
335{
336 typeof_member(struct proc_ops, proc_poll) poll;
337
338 poll = pde->proc_ops->proc_poll;
339 if (poll)
340 return poll(file, pts);
341 return DEFAULT_POLLMASK;
342}
343
308static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)344static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
309{345{
310 struct proc_dir_entry *pde = PDE(file_inode(file));346 struct proc_dir_entry *pde = PDE(file_inode(file));
311 __poll_t rv = DEFAULT_POLLMASK;347 __poll_t rv = DEFAULT_POLLMASK;
312 if (use_pde(pde)) {
313 typeof_member(struct proc_ops, proc_poll) poll;
314 348
315 poll = pde->proc_ops->proc_poll;349 if (pde_is_permanent(pde)) {
316 if (poll)350 return pde_poll(pde, file, pts);
317 rv = poll(file, pts);351 } else if (use_pde(pde)) {
352 rv = pde_poll(pde, file, pts);
318 unuse_pde(pde);353 unuse_pde(pde);
319 }354 }
320 return rv;355 return rv;
321}356}
322 357
358static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg)
359{
360 typeof_member(struct proc_ops, proc_ioctl) ioctl;
361
362 ioctl = pde->proc_ops->proc_ioctl;
363 if (ioctl)
364 return ioctl(file, cmd, arg);
365 return -ENOTTY;
366}
367
323static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)368static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
324{369{
325 struct proc_dir_entry *pde = PDE(file_inode(file));370 struct proc_dir_entry *pde = PDE(file_inode(file));
326 long rv = -ENOTTY;371 long rv = -ENOTTY;
327 if (use_pde(pde)) {
328 typeof_member(struct proc_ops, proc_ioctl) ioctl;
329 372
330 ioctl = pde->proc_ops->proc_ioctl;373 if (pde_is_permanent(pde)) {
331 if (ioctl)374 return pde_ioctl(pde, file, cmd, arg);
332 rv = ioctl(file, cmd, arg);375 } else if (use_pde(pde)) {
376 rv = pde_ioctl(pde, file, cmd, arg);
333 unuse_pde(pde);377 unuse_pde(pde);
334 }378 }
335 return rv;379 return rv;
336}380}
337 381
338#ifdef CONFIG_COMPAT382#ifdef CONFIG_COMPAT
383static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg)
384{
385 typeof_member(struct proc_ops, proc_compat_ioctl) compat_ioctl;
386
387 compat_ioctl = pde->proc_ops->proc_compat_ioctl;
388 if (compat_ioctl)
389 return compat_ioctl(file, cmd, arg);
390 return -ENOTTY;
391}
392
339static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)393static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
340{394{
341 struct proc_dir_entry *pde = PDE(file_inode(file));395 struct proc_dir_entry *pde = PDE(file_inode(file));
342 long rv = -ENOTTY;396 long rv = -ENOTTY;
343 if (use_pde(pde)) {397 if (pde_is_permanent(pde)) {
344 typeof_member(struct proc_ops, proc_compat_ioctl) compat_ioctl;398 return pde_compat_ioctl(pde, file, cmd, arg);
345 399 } else if (use_pde(pde)) {
346 compat_ioctl = pde->proc_ops->proc_compat_ioctl;400 rv = pde_compat_ioctl(pde, file, cmd, arg);
347 if (compat_ioctl)
348 rv = compat_ioctl(file, cmd, arg);
349 unuse_pde(pde);401 unuse_pde(pde);
350 }402 }
351 return rv;403 return rv;
352}404}
353#endif405#endif
354 406
407static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_area_struct *vma)
408{
409 typeof_member(struct proc_ops, proc_mmap) mmap;
410
411 mmap = pde->proc_ops->proc_mmap;
412 if (mmap)
413 return mmap(file, vma);
414 return -EIO;
415}
416
355static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)417static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
356{418{
357 struct proc_dir_entry *pde = PDE(file_inode(file));419 struct proc_dir_entry *pde = PDE(file_inode(file));
358 int rv = -EIO;420 int rv = -EIO;
359 if (use_pde(pde)) {
360 typeof_member(struct proc_ops, proc_mmap) mmap;
361 421
362 mmap = pde->proc_ops->proc_mmap;422 if (pde_is_permanent(pde)) {
363 if (mmap)423 return pde_mmap(pde, file, vma);
364 rv = mmap(file, vma);424 } else if (use_pde(pde)) {
425 rv = pde_mmap(pde, file, vma);
365 unuse_pde(pde);426 unuse_pde(pde);
366 }427 }
367 return rv;428 return rv;
368}429}
369 430
370static unsigned long431static unsigned long
371proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,432pde_get_unmapped_area(struct proc_dir_entry *pde, struct file *file, unsigned long orig_addr,
372 unsigned long len, unsigned long pgoff,433 unsigned long len, unsigned long pgoff,
373 unsigned long flags)434 unsigned long flags)
374{435{
375 struct proc_dir_entry *pde = PDE(file_inode(file));436 typeof_member(struct proc_ops, proc_get_unmapped_area) get_area;
376 unsigned long rv = -EIO;
377
378 if (use_pde(pde)) {
379 typeof_member(struct proc_ops, proc_get_unmapped_area) get_area;
380 437
381 get_area = pde->proc_ops->proc_get_unmapped_area;438 get_area = pde->proc_ops->proc_get_unmapped_area;
382#ifdef CONFIG_MMU439#ifdef CONFIG_MMU
383 if (!get_area)440 if (!get_area)
384 get_area = current->mm->get_unmapped_area;441 get_area = current->mm->get_unmapped_area;
385#endif442#endif
443 if (get_area)
444 return get_area(file, orig_addr, len, pgoff, flags);
445 return orig_addr;
446}
447
448static unsigned long
449proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
450 unsigned long len, unsigned long pgoff,
451 unsigned long flags)
452{
453 struct proc_dir_entry *pde = PDE(file_inode(file));
454 unsigned long rv = -EIO;
386 455
387 if (get_area)456 if (pde_is_permanent(pde)) {
388 rv = get_area(file, orig_addr, len, pgoff, flags);457 return pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
389 else458 } else if (use_pde(pde)) {
390 rv = orig_addr;459 rv = pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
391 unuse_pde(pde);460 unuse_pde(pde);
392 }461 }
393 return rv;462 return rv;
@@ -401,6 +470,13 @@ static int proc_reg_open(struct inode *inode, struct file *file) · 7 unmodified lines
401 typeof_member(struct proc_ops, proc_release) release;470 typeof_member(struct proc_ops, proc_release) release;
402 struct pde_opener *pdeo;471 struct pde_opener *pdeo;
403 472
473 if (pde_is_permanent(pde)) {
474 open = pde->proc_ops->proc_open;
475 if (open)
476 rv = open(inode, file);
477 return rv;
478 }
479
404 /*480 /*
405 * Ensure that481 * Ensure that
406 * 1) PDE's ->release hook will be called no matter what482 * 1) PDE's ->release hook will be called no matter what
@@ -450,6 +526,17 @@ static int proc_reg_release(struct inode *inode, struct file *file) · 43 unmodified lines
450{526{
451 struct proc_dir_entry *pde = PDE(inode);527 struct proc_dir_entry *pde = PDE(inode);
452 struct pde_opener *pdeo;528 struct pde_opener *pdeo;
529
530 if (pde_is_permanent(pde)) {
531 typeof_member(struct proc_ops, proc_release) release;
532
533 release = pde->proc_ops->proc_release;
534 if (release) {
535 return release(inode, file);
536 }
537 return 0;
538 }
539
453 spin_lock(&pde->pde_unload_lock);540 spin_lock(&pde->pde_unload_lock);
454 list_for_each_entry(pdeo, &pde->pde_openers, lh) {541 list_for_each_entry(pdeo, &pde->pde_openers, lh) {
455 if (pdeo->file == file) {542 if (pdeo->file == file) {
fs/proc/internal.h+6−0
@@ -61,6 +61,7 @@ struct proc_dir_entry { · 60 unmodified lines
61 struct rb_node subdir_node;61 struct rb_node subdir_node;
62 char *name;62 char *name;
63 umode_t mode;63 umode_t mode;
64 u8 flags;
64 u8 namelen;65 u8 namelen;
65 char inline_name[];66 char inline_name[];
66} __randomize_layout;67} __randomize_layout;
@@ -73,6 +74,11 @@ struct proc_dir_entry { · 6 unmodified lines
73 0)74 0)
74#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE - sizeof(struct proc_dir_entry))75#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE - sizeof(struct proc_dir_entry))
75 76
77static inline bool pde_is_permanent(const struct proc_dir_entry *pde)
78{
79 return pde->flags & PROC_ENTRY_PERMANENT;
80}
81
76extern struct kmem_cache *proc_dir_entry_cache;82extern struct kmem_cache *proc_dir_entry_cache;
77void pde_free(struct proc_dir_entry *pde);83void pde_free(struct proc_dir_entry *pde);
78 84
fs/proc/kmsg.c+1−0
@@ -50,6 +50,7 @@ static __poll_t kmsg_poll(struct file *file, poll_table *wait) · 49 unmodified lines
50 50
51 51
52static const struct proc_ops kmsg_proc_ops = {52static const struct proc_ops kmsg_proc_ops = {
53 .proc_flags = PROC_ENTRY_PERMANENT,
53 .proc_read = kmsg_read,54 .proc_read = kmsg_read,
54 .proc_poll = kmsg_poll,55 .proc_poll = kmsg_poll,
55 .proc_open = kmsg_open,56 .proc_open = kmsg_open,
fs/proc/stat.c+1−0
@@ -224,6 +224,7 @@ static int stat_open(struct inode *inode, struct file *file) · 223 unmodified lines
224}224}
225 225
226static const struct proc_ops stat_proc_ops = {226static const struct proc_ops stat_proc_ops = {
227 .proc_flags = PROC_ENTRY_PERMANENT,
227 .proc_open = stat_open,228 .proc_open = stat_open,
228 .proc_read = seq_read,229 .proc_read = seq_read,
229 .proc_lseek = seq_lseek,230 .proc_lseek = seq_lseek,
include/linux/proc_fs.h+16−1
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#ifndef _LINUX_PROC_FS_H5#ifndef _LINUX_PROC_FS_H
6#define _LINUX_PROC_FS_H6#define _LINUX_PROC_FS_H
7 7
8#include <linux/compiler.h>
8#include <linux/types.h>9#include <linux/types.h>
9#include <linux/fs.h>10#include <linux/fs.h>
10 11
@@ -12,7 +13,21 @@ struct proc_dir_entry; · 1 unmodified line
12struct seq_file;13struct seq_file;
13struct seq_operations;14struct seq_operations;
14 15
16enum {
17 /*
18 * All /proc entries using this ->proc_ops instance are never removed.
19 *
20 * If in doubt, ignore this flag.
21 */
22#ifdef MODULE
23 PROC_ENTRY_PERMANENT = 0U,
24#else
25 PROC_ENTRY_PERMANENT = 1U << 0,
26#endif
27};
28
15struct proc_ops {29struct proc_ops {
30 unsigned int proc_flags;
16 int (*proc_open)(struct inode *, struct file *);31 int (*proc_open)(struct inode *, struct file *);
17 ssize_t (*proc_read)(struct file *, char __user *, size_t, loff_t *);32 ssize_t (*proc_read)(struct file *, char __user *, size_t, loff_t *);
18 ssize_t (*proc_write)(struct file *, const char __user *, size_t, loff_t *);33 ssize_t (*proc_write)(struct file *, const char __user *, size_t, loff_t *);
@@ -25,7 +40,7 @@ struct proc_ops { · 6 unmodified lines
25#endif40#endif
26 int (*proc_mmap)(struct file *, struct vm_area_struct *);41 int (*proc_mmap)(struct file *, struct vm_area_struct *);
27 unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);42 unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
28};43} __randomize_layout;
29 44
30#ifdef CONFIG_PROC_FS45#ifdef CONFIG_PROC_FS
31 46
ipc/util.c+1−0
@@ -885,6 +885,7 @@ static int sysvipc_proc_release(struct inode *inode, struct file *file) · 884 unmodified lines
885}885}
886 886
887static const struct proc_ops sysvipc_proc_ops = {887static const struct proc_ops sysvipc_proc_ops = {
888 .proc_flags = PROC_ENTRY_PERMANENT,
888 .proc_open = sysvipc_proc_open,889 .proc_open = sysvipc_proc_open,
889 .proc_read = seq_read,890 .proc_read = seq_read,
890 .proc_lseek = seq_lseek,891 .proc_lseek = seq_lseek,
kernel/module.c+1−0
@@ -4355,6 +4355,7 @@ static int modules_open(struct inode *inode, struct file *file) · 4354 unmodified lines
4355}4355}
4356 4356
4357static const struct proc_ops modules_proc_ops = {4357static const struct proc_ops modules_proc_ops = {
4358 .proc_flags = PROC_ENTRY_PERMANENT,
4358 .proc_open = modules_open,4359 .proc_open = modules_open,
4359 .proc_read = seq_read,4360 .proc_read = seq_read,
4360 .proc_lseek = seq_lseek,4361 .proc_lseek = seq_lseek,
mm/slab_common.c+1−0
@@ -1581,6 +1581,7 @@ static int slabinfo_open(struct inode *inode, struct file *file) · 1580 unmodified lines
1581}1581}
1582 1582
1583static const struct proc_ops slabinfo_proc_ops = {1583static const struct proc_ops slabinfo_proc_ops = {
1584 .proc_flags = PROC_ENTRY_PERMANENT,
1584 .proc_open = slabinfo_open,1585 .proc_open = slabinfo_open,
1585 .proc_read = seq_read,1586 .proc_read = seq_read,
1586 .proc_write = slabinfo_write,1587 .proc_write = slabinfo_write,
mm/swapfile.c+1−0
@@ -2797,6 +2797,7 @@ static int swaps_open(struct inode *inode, struct file *file) · 2796 unmodified lines
2797}2797}
2798 2798
2799static const struct proc_ops swaps_proc_ops = {2799static const struct proc_ops swaps_proc_ops = {
2800 .proc_flags = PROC_ENTRY_PERMANENT,
2800 .proc_open = swaps_open,2801 .proc_open = swaps_open,
2801 .proc_read = seq_read,2802 .proc_read = seq_read,
2802 .proc_lseek = seq_lseek,2803 .proc_lseek = seq_lseek,