An ls and a wc commands show 0 size for some of /proc/<PID>/* files, because getattr methods and inode->i_size variables are not implemented for these files. These files are known pseudo, but some peoples may need size of the files. To calculate and return the size of each /proc/<PID>/auxv, proc_pid_auxv_getattr() is added. It is used when getattr() system call for the /proc/<PID>/auxv is called. To initialize inode->i_size of each /proc/<PID>/* file, isize_initializer member of pid_entry and some macros are added, and proc_pid_auxv_isize() is added for i_size of each /proc/<PID>/auxv. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=155943 Signed-off-by: Takayuki Nagata <tnagata@xxxxxxxxxx> --- fs/proc/base.c | 66 +++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 51 insertions(+), 15 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index fc5bc27..e45afd3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -105,33 +105,37 @@ struct pid_entry { const struct inode_operations *iop; const struct file_operations *fop; union proc_op op; + loff_t (*isize_initializer)(struct task_struct*); }; -#define NOD(NAME, MODE, IOP, FOP, OP) { \ +#define NOD(NAME, MODE, IOP, FOP, OP, ISIZE) { \ .name = (NAME), \ .len = sizeof(NAME) - 1, \ .mode = MODE, \ .iop = IOP, \ .fop = FOP, \ .op = OP, \ + .isize_initializer = ISIZE, \ } #define DIR(NAME, MODE, iops, fops) \ - NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} ) + NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {}, NULL ) #define LNK(NAME, get_link) \ NOD(NAME, (S_IFLNK|S_IRWXUGO), \ &proc_pid_link_inode_operations, NULL, \ - { .proc_get_link = get_link } ) + { .proc_get_link = get_link }, NULL ) #define REG(NAME, MODE, fops) \ - NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) + NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}, NULL ) +#define INF_WITH_IOP(NAME, MODE, read, iop, isize) \ + NOD(NAME, (S_IFREG|(MODE)), \ + iop, &proc_info_file_operations, \ + { .proc_read = read }, isize ) #define INF(NAME, MODE, read) \ - NOD(NAME, (S_IFREG|(MODE)), \ - NULL, &proc_info_file_operations, \ - { .proc_read = read } ) + INF_WITH_IOP(NAME, MODE, read, NULL, NULL ) #define ONE(NAME, MODE, show) \ NOD(NAME, (S_IFREG|(MODE)), \ NULL, &proc_single_file_operations, \ - { .proc_show = show } ) + { .proc_show = show }, NULL ) /* * Count the number of hardlinks for the pid_entry table, excluding the . @@ -309,9 +313,8 @@ out: return res; } -static int proc_pid_auxv(struct task_struct *task, char *buffer) +inline static int count_mm_saved_auxv(struct mm_struct *mm) { - struct mm_struct *mm = mm_for_maps(task); int res = PTR_ERR(mm); if (mm && !IS_ERR(mm)) { unsigned int nwords = 0; @@ -321,12 +324,43 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer) res = nwords * sizeof(mm->saved_auxv[0]); if (res > PAGE_SIZE) res = PAGE_SIZE; - memcpy(buffer, mm->saved_auxv, res); - mmput(mm); } return res; } +static int proc_pid_auxv(struct task_struct *task, char *buffer) +{ + int size; + struct mm_struct *mm = get_task_mm(task); + size = count_mm_saved_auxv(mm); + if (mm) { + if(buffer) + memcpy(buffer, mm->saved_auxv, size); + mmput(mm); + } + return size; +} + +static loff_t proc_pid_auxv_isize(struct task_struct *task) +{ + struct mm_struct *mm = get_task_mm(task); + return count_mm_saved_auxv(mm); +} + +static int proc_pid_auxv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + struct task_struct *task = get_proc_task(inode); + struct mm_struct *mm = get_task_mm(task); + + generic_fillattr(inode, stat); + stat->size = count_mm_saved_auxv(mm); + return 0; +} + +static struct inode_operations proc_pid_auxv_inode_operations = { + .getattr = proc_pid_auxv_getattr, +}; #ifdef CONFIG_KALLSYMS /* @@ -2253,6 +2287,8 @@ static struct dentry *proc_pident_instantiate(struct inode *dir, ei = PROC_I(inode); inode->i_mode = p->mode; + if (p->isize_initializer) + inode->i_size = p->isize_initializer(task); if (S_ISDIR(inode->i_mode)) inode->i_nlink = 2; /* Use getattr to fix if necessary */ if (p->iop) @@ -2617,7 +2653,7 @@ static const struct inode_operations proc_self_inode_operations = { */ static const struct pid_entry proc_base_stuff[] = { NOD("self", S_IFLNK|S_IRWXUGO, - &proc_self_inode_operations, NULL, {}), + &proc_self_inode_operations, NULL, {}, NULL), }; static struct dentry *proc_base_instantiate(struct inode *dir, @@ -2774,7 +2810,7 @@ static const struct pid_entry tgid_base_stuff[] = { DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), #endif REG("environ", S_IRUSR, proc_environ_operations), - INF("auxv", S_IRUSR, proc_pid_auxv), + INF_WITH_IOP("auxv", S_IRUSR, proc_pid_auxv, &proc_pid_auxv_inode_operations, proc_pid_auxv_isize), ONE("status", S_IRUGO, proc_pid_status), ONE("personality", S_IRUGO, proc_pid_personality), INF("limits", S_IRUGO, proc_pid_limits), @@ -3123,7 +3159,7 @@ static const struct pid_entry tid_base_stuff[] = { DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), REG("environ", S_IRUSR, proc_environ_operations), - INF("auxv", S_IRUSR, proc_pid_auxv), + INF_WITH_IOP("auxv", S_IRUSR, proc_pid_auxv, &proc_pid_auxv_inode_operations, proc_pid_auxv_isize), ONE("status", S_IRUGO, proc_pid_status), ONE("personality", S_IRUGO, proc_pid_personality), INF("limits", S_IRUGO, proc_pid_limits), -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html