diff -urN linux-2.6.5-orig/Documentation/filesystems/proc.txt linux-2.6.5/Documentation/filesystems/proc.txt --- linux-2.6.5-orig/Documentation/filesystems/proc.txt 2004-04-09 15:06:48.000000000 +0100 +++ linux-2.6.5/Documentation/filesystems/proc.txt 2004-04-10 20:43:56.000000000 +0100 @@ -130,6 +130,7 @@ root Link to the root directory of this process stat Process status statm Process memory status information + statfd Status of the processes file descriptors status Process status in human readable form wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan .............................................................................. @@ -180,6 +181,13 @@ dt number of dirty pages .............................................................................. +The statfd contains one line per open file descriptor in the process - for +example: +16 821409 02 0x44009 0 + +Is file descriptor 16, that is 821409 bytes into the file, has a mode of 02 (octal), +has flags 0x44009 and no error. + 1.2 Kernel data --------------- diff -urN linux-2.6.5-orig/fs/proc/base.c linux-2.6.5/fs/proc/base.c --- linux-2.6.5-orig/fs/proc/base.c 2004-04-09 15:07:04.000000000 +0100 +++ linux-2.6.5/fs/proc/base.c 2004-04-10 20:34:12.000000000 +0100 @@ -57,6 +57,7 @@ PROC_TGID_CMDLINE, PROC_TGID_STAT, PROC_TGID_STATM, + PROC_TGID_STATFD, PROC_TGID_MAPS, PROC_TGID_MOUNTS, PROC_TGID_WCHAN, @@ -80,6 +81,7 @@ PROC_TID_CMDLINE, PROC_TID_STAT, PROC_TID_STATM, + PROC_TID_STATFD, PROC_TID_MAPS, PROC_TID_MOUNTS, PROC_TID_WCHAN, @@ -111,6 +113,7 @@ E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), + E(PROC_TGID_STATFD, "statfd", S_IFREG|S_IRUSR), E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO), @@ -133,6 +136,7 @@ E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), + E(PROC_TID_STATFD, "statfd", S_IFREG|S_IRUGO), E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO), @@ -167,6 +171,12 @@ #undef E +static int pid_alive(struct task_struct *p) +{ + BUG_ON(p->pids[PIDTYPE_PID].pidptr != &p->pids[PIDTYPE_PID].pid); + return atomic_read(&p->pids[PIDTYPE_PID].pid.count); +} + static inline struct task_struct *proc_task(struct inode *inode) { return PROC_I(inode)->task; @@ -513,6 +523,162 @@ .release = mounts_release, }; +/* ------------------------------------------------------------------------ + * statfd: A file containing one line of information per open file + * We use the seq_file stuff to let us construct the file on the fly + * The seq_file's private member contains a pointer to a pid_statfd_temps + * The 'v' pointer contains the last loff_t pointer we were given (safe??) + * + * (Derived from a mix of the code to do the fd directory, the + * pid/map file and LWN article 22355) + * Dave Gilbert (linux@treblig.org) + */ + +struct pid_statfd_temps { + struct task_struct* task; + struct files_struct* files; +}; + +static void *statfd_start(struct seq_file *m, loff_t *pos) +{ + struct pid_statfd_temps* temps=(struct pid_statfd_temps*)m->private; + struct task_struct *task = temps->task; + int max_fds; + + if (!pid_alive(task)) + return NULL; + + /* Get hold of the files structure from the task */ + task_lock(task); + temps->files = task->files; + if (temps->files) + atomic_inc(&temps->files->count); /* stop it being freed while we've got it */ + task_unlock(task); + + /* Check to see if we are off the end */ + spin_lock(&temps->files->file_lock); + max_fds=temps->files->max_fds; + spin_unlock(&temps->files->file_lock); + + if (*pos >= max_fds) + { + return NULL; + } + + return pos; +} + +static void statfd_stop(struct seq_file *m, void *v) +{ + struct pid_statfd_temps* temps=(struct pid_statfd_temps*)m->private; + + if (temps->files) + { + /* Release if they are finished with */ + put_files_struct(temps->files); + temps->files=NULL; + } +} + +static void *statfd_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct pid_statfd_temps* temps=(struct pid_statfd_temps*)m->private; + + int max_fds; + + /* Check to see if we are off the end */ + spin_lock(&temps->files->file_lock); + max_fds=temps->files->max_fds; + spin_unlock(&temps->files->file_lock); + + /* Lets try another one, and if OK just return the same pointer */ + if (++(*pos) < max_fds) + { + return pos; + } + + /* Have to release locks etc before we tell seq_file we're done */ + statfd_stop(m,v); + return NULL; +} + +static int statfd_show(struct seq_file *m, void *v) +{ + struct pid_statfd_temps* temps=(struct pid_statfd_temps*)m->private; + int fd; + struct file* file; + + loff_t f_pos; + mode_t f_mode; + int f_error; + unsigned int f_flags; + + fd=(int)*(loff_t*)v; + + spin_lock(&temps->files->file_lock); + file = fcheck_files(temps->files, fd); + + if (file) { + f_pos=file->f_pos; + f_mode=file->f_mode; + f_error=file->f_error; + f_flags=file->f_flags; + } + + spin_unlock(&temps->files->file_lock); + + if (file) + seq_printf(m,"%d %lld 0%o 0x%x %d\n",fd, (long long)f_pos, f_mode, f_flags, f_error); + + return 0; +} + +static struct seq_operations proc_pid_statfd_seqop = { + .start = statfd_start, + .next = statfd_next, + .stop = statfd_stop, + .show = statfd_show +}; + +static int pid_statfd_open(struct inode *inode, struct file *file) +{ + struct pid_statfd_temps* temps=kmalloc(sizeof(*temps), GFP_KERNEL); + if (!temps) + return -ENOMEM; + + temps->task = proc_task(inode); + temps->files = NULL; + + int ret = seq_open(file, &proc_pid_statfd_seqop); + if (!ret) { + struct seq_file *m = file->private_data; + m->private = temps; + } else { + kfree(temps); + } + + return ret; +} + +static int pid_statfd_release(struct inode *inode, struct file *file) +{ + /* We need to clean up the temporary we allocated in pid_statfd_open + * and then let seq_release do its cleanup */ + struct seq_file *m = file->private_data; + struct pid_statfd_temps* temps = m->private; + kfree(temps); + return seq_release(inode, file); +} + +static struct file_operations proc_pid_statfd_operations = { + .open = pid_statfd_open, + .read = seq_read, + .llseek = seq_lseek, + .release = pid_statfd_release +}; + +/* ------------------------------------------------------------------------ */ + #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static ssize_t proc_info_read(struct file * file, char * buf, @@ -771,12 +937,6 @@ .follow_link = proc_pid_follow_link }; -static int pid_alive(struct task_struct *p) -{ - BUG_ON(p->pids[PIDTYPE_PID].pidptr != &p->pids[PIDTYPE_PID].pid); - return atomic_read(&p->pids[PIDTYPE_PID].pid.count); -} - #define NUMBUF 10 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) @@ -1349,6 +1509,10 @@ inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_statm; break; + case PROC_TID_STATFD: + case PROC_TGID_STATFD: + inode->i_fop = &proc_pid_statfd_operations; + break; case PROC_TID_MAPS: case PROC_TGID_MAPS: inode->i_fop = &proc_maps_operations;