Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
c4185a0
Documentation
arch
block
crypto
drivers
fs
9p
adfs
affs
afs
autofs
autofs4
befs
bfs
cifs
coda
configfs
cramfs
debugfs
devpts
dlm
ecryptfs
efs
exportfs
ext2
ext3
ext4
fat
freevxfs
fuse
gfs2
hfs
hfsplus
hostfs
hpfs
hppfs
hugetlbfs
isofs
jbd
jbd2
jffs2
jfs
lockd
minix
msdos
ncpfs
nfs
nfs_common
nfsd
nls
ntfs
ocfs2
openpromfs
partitions
proc
Makefile
array.c
base.c
generic.c
inode-alloc.txt
inode.c
internal.h
kcore.c
kmsg.c
mmu.c
nommu.c
proc_devtree.c
proc_misc.c
proc_net.c
proc_sysctl.c
proc_tty.c
root.c
task_mmu.c
task_nommu.c
vmcore.c
qnx4
ramfs
reiserfs
romfs
smbfs
sysfs
sysv
udf
ufs
vfat
xfs
Kconfig
Kconfig.binfmt
Makefile
aio.c
anon_inodes.c
attr.c
bad_inode.c
binfmt_aout.c
binfmt_elf.c
binfmt_elf_fdpic.c
binfmt_em86.c
binfmt_flat.c
binfmt_misc.c
binfmt_script.c
binfmt_som.c
bio.c
block_dev.c
buffer.c
char_dev.c
compat.c
compat_binfmt_elf.c
compat_ioctl.c
dcache.c
dcookies.c
direct-io.c
dnotify.c
dquot.c
drop_caches.c
eventfd.c
eventpoll.c
exec.c
fcntl.c
fifo.c
file.c
file_table.c
filesystems.c
fs-writeback.c
generic_acl.c
inode.c
inotify.c
inotify_user.c
internal.h
ioctl.c
ioprio.c
libfs.c
locks.c
mbcache.c
mpage.c
namei.c
namespace.c
nfsctl.c
no-block.c
open.c
pipe.c
pnode.c
pnode.h
posix_acl.c
quota.c
quota_v1.c
quota_v2.c
read_write.c
read_write.h
readdir.c
select.c
seq_file.c
signalfd.c
splice.c
stack.c
stat.c
super.c
sync.c
timerfd.c
utimes.c
xattr.c
xattr_acl.c
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
fs
/
proc
/
inode.c
Copy path
Blame
Blame
Latest commit
History
History
465 lines (397 loc) · 10.4 KB
Breadcrumbs
linux
/
fs
/
proc
/
inode.c
Top
File metadata and controls
Code
Blame
465 lines (397 loc) · 10.4 KB
Raw
/* * linux/fs/proc/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <linux/time.h> #include <linux/proc_fs.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/completion.h> #include <linux/poll.h> #include <linux/file.h> #include <linux/limits.h> #include <linux/init.h> #include <linux/module.h> #include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> #include "internal.h" struct proc_dir_entry *de_get(struct proc_dir_entry *de) { atomic_inc(&de->count); return de; } /* * Decrements the use count and checks for deferred deletion. */ void de_put(struct proc_dir_entry *de) { lock_kernel(); if (!atomic_read(&de->count)) { printk("de_put: entry %s already free!\n", de->name); unlock_kernel(); return; } if (atomic_dec_and_test(&de->count)) free_proc_entry(de); unlock_kernel(); } /* * Decrement the use count of the proc_dir_entry. */ static void proc_delete_inode(struct inode *inode) { struct proc_dir_entry *de; truncate_inode_pages(&inode->i_data, 0); /* Stop tracking associated processes */ put_pid(PROC_I(inode)->pid); /* Let go of any associated proc directory entry */ de = PROC_I(inode)->pde; if (de) { if (de->owner) module_put(de->owner); de_put(de); } clear_inode(inode); } struct vfsmount *proc_mnt; static struct kmem_cache * proc_inode_cachep; static struct inode *proc_alloc_inode(struct super_block *sb) { struct proc_inode *ei; struct inode *inode; ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL); if (!ei) return NULL; ei->pid = NULL; ei->fd = 0; ei->op.proc_get_link = NULL; ei->pde = NULL; inode = &ei->vfs_inode; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; return inode; } static void proc_destroy_inode(struct inode *inode) { kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } static void init_once(struct kmem_cache * cachep, void *foo) { struct proc_inode *ei = (struct proc_inode *) foo; inode_init_once(&ei->vfs_inode); } int __init proc_init_inodecache(void) { proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_PANIC), init_once); return 0; } static int proc_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_NODIRATIME; return 0; } static const struct super_operations proc_sops = { .alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, .drop_inode = generic_delete_inode, .delete_inode = proc_delete_inode, .statfs = simple_statfs, .remount_fs = proc_remount, }; static void pde_users_dec(struct proc_dir_entry *pde) { spin_lock(&pde->pde_unload_lock); pde->pde_users--; if (pde->pde_unload_completion && pde->pde_users == 0) complete(pde->pde_unload_completion); spin_unlock(&pde->pde_unload_lock); } static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); loff_t rv = -EINVAL; loff_t (*llseek)(struct file *, loff_t, int); spin_lock(&pde->pde_unload_lock); /* * remove_proc_entry() is going to delete PDE (as part of module * cleanup sequence). No new callers into module allowed. */ if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } /* * Bump refcount so that remove_proc_entry will wail for ->llseek to * complete. */ pde->pde_users++; /* * Save function pointer under lock, to protect against ->proc_fops * NULL'ifying right after ->pde_unload_lock is dropped. */ llseek = pde->proc_fops->llseek; spin_unlock(&pde->pde_unload_lock); if (!llseek) llseek = default_llseek; rv = llseek(file, offset, whence); pde_users_dec(pde); return rv; } static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); ssize_t rv = -EIO; ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; read = pde->proc_fops->read; spin_unlock(&pde->pde_unload_lock); if (read) rv = read(file, buf, count, ppos); pde_users_dec(pde); return rv; } static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); ssize_t rv = -EIO; ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; write = pde->proc_fops->write; spin_unlock(&pde->pde_unload_lock); if (write) rv = write(file, buf, count, ppos); pde_users_dec(pde); return rv; } static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); unsigned int rv = DEFAULT_POLLMASK; unsigned int (*poll)(struct file *, struct poll_table_struct *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; poll = pde->proc_fops->poll; spin_unlock(&pde->pde_unload_lock); if (poll) rv = poll(file, pts); pde_users_dec(pde); return rv; } static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); long rv = -ENOTTY; long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; unlocked_ioctl = pde->proc_fops->unlocked_ioctl; ioctl = pde->proc_fops->ioctl; spin_unlock(&pde->pde_unload_lock); if (unlocked_ioctl) { rv = unlocked_ioctl(file, cmd, arg); if (rv == -ENOIOCTLCMD) rv = -EINVAL; } else if (ioctl) { lock_kernel(); rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg); unlock_kernel(); } pde_users_dec(pde); return rv; } #ifdef CONFIG_COMPAT static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); long rv = -ENOTTY; long (*compat_ioctl)(struct file *, unsigned int, unsigned long); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; compat_ioctl = pde->proc_fops->compat_ioctl; spin_unlock(&pde->pde_unload_lock); if (compat_ioctl) rv = compat_ioctl(file, cmd, arg); pde_users_dec(pde); return rv; } #endif static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); int rv = -EIO; int (*mmap)(struct file *, struct vm_area_struct *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; mmap = pde->proc_fops->mmap; spin_unlock(&pde->pde_unload_lock); if (mmap) rv = mmap(file, vma); pde_users_dec(pde); return rv; } static int proc_reg_open(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); int rv = 0; int (*open)(struct inode *, struct file *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; open = pde->proc_fops->open; spin_unlock(&pde->pde_unload_lock); if (open) rv = open(inode, file); pde_users_dec(pde); return rv; } static int proc_reg_release(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); int rv = 0; int (*release)(struct inode *, struct file *); spin_lock(&pde->pde_unload_lock); if (!pde->proc_fops) { spin_unlock(&pde->pde_unload_lock); return rv; } pde->pde_users++; release = pde->proc_fops->release; spin_unlock(&pde->pde_unload_lock); if (release) rv = release(inode, file); pde_users_dec(pde); return rv; } static const struct file_operations proc_reg_file_ops = { .llseek = proc_reg_llseek, .read = proc_reg_read, .write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = proc_reg_compat_ioctl, #endif .mmap = proc_reg_mmap, .open = proc_reg_open, .release = proc_reg_release, }; #ifdef CONFIG_COMPAT static const struct file_operations proc_reg_file_ops_no_compat = { .llseek = proc_reg_llseek, .read = proc_reg_read, .write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, .mmap = proc_reg_mmap, .open = proc_reg_open, .release = proc_reg_release, }; #endif struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, struct proc_dir_entry *de) { struct inode * inode; if (!try_module_get(de->owner)) goto out_mod; inode = iget_locked(sb, ino); if (!inode) goto out_ino; if (inode->i_state & I_NEW) { inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; PROC_I(inode)->fd = 0; PROC_I(inode)->pde = de; if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; inode->i_gid = de->gid; } if (de->size) inode->i_size = de->size; if (de->nlink) inode->i_nlink = de->nlink; if (de->proc_iops) inode->i_op = de->proc_iops; if (de->proc_fops) { if (S_ISREG(inode->i_mode)) { #ifdef CONFIG_COMPAT if (!de->proc_fops->compat_ioctl) inode->i_fop = &proc_reg_file_ops_no_compat; else #endif inode->i_fop = &proc_reg_file_ops; } else { inode->i_fop = de->proc_fops; } } unlock_new_inode(inode); } else module_put(de->owner); return inode; out_ino: module_put(de->owner); out_mod: return NULL; } int proc_fill_super(struct super_block *s) { struct inode * root_inode; s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; s->s_time_gran = 1; de_get(&proc_root); root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; root_inode->i_uid = 0; root_inode->i_gid = 0; s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; return 0; out_no_root: printk("proc_read_super: get root inode failed\n"); iput(root_inode); de_put(&proc_root); return -ENOMEM; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
You can’t perform that action at this time.