Diff below introduces a new helper function to iterate on `filehead'.
This global data structures contains a reference to living 'struct file *'
so its access must be serialized with fdrop(). This is what the comment
below explains. Currently the serialization is done by the KERNEL_LOCK(),
but since I'd like to remove the KERNEL_LOCK() from syscalls that call
FRELE(9) we'll need to use another lock. So having all the accesses to
`filehead' in the same place makes it easier.
Ok?
Index: kern/kern_descrip.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.150
diff -u -p -r1.150 kern_descrip.c
--- kern/kern_descrip.c 12 Apr 2018 10:30:18 -0000 1.150
+++ kern/kern_descrip.c 17 Apr 2018 07:51:51 -0000
@@ -180,6 +180,28 @@ fd_unused(struct filedesc *fdp, int fd)
}
struct file *
+fd_iterfile(struct file *fp, struct proc *p)
+{
+ struct file *nfp;
+
+ if (fp == NULL)
+ nfp = LIST_FIRST(&filehead);
+ else
+ nfp = LIST_NEXT(fp, f_list);
+
+ /* don't FREF when f_count == 0 to avoid race in fdrop() */
+ while (nfp != NULL && nfp->f_count == 0)
+ nfp = LIST_NEXT(nfp, f_list);
+ if (nfp != NULL)
+ FREF(nfp);
+
+ if (fp != NULL)
+ FRELE(fp, p);
+
+ return nfp;
+}
+
+struct file *
fd_getfile(struct filedesc *fdp, int fd)
{
struct file *fp;
Index: kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.332
diff -u -p -r1.332 kern_sysctl.c
--- kern/kern_sysctl.c 19 Feb 2018 08:59:52 -0000 1.332
+++ kern/kern_sysctl.c 16 Apr 2018 12:43:19 -0000
@@ -1250,7 +1250,7 @@ sysctl_file(int *name, u_int namelen, ch
{
struct kinfo_file *kf;
struct filedesc *fdp;
- struct file *fp, *nfp;
+ struct file *fp;
struct process *pr;
size_t buflen, elem_size, elem_count, outsize;
char *dp = where;
@@ -1318,14 +1318,8 @@ sysctl_file(int *name, u_int namelen, ch
#endif
NET_UNLOCK();
}
- fp = LIST_FIRST(&filehead);
- /* don't FREF when f_count == 0 to avoid race in fdrop() */
- while (fp != NULL && fp->f_count == 0)
- fp = LIST_NEXT(fp, f_list);
- if (fp == NULL)
- break;
- FREF(fp);
- do {
+ fp = NULL; ;
+ while ((fp = fd_iterfile(fp, p)) != NULL) {
if (fp->f_count > 1 && /* 0, +1 for our FREF() */
FILE_IS_USABLE(fp) &&
(arg == 0 || fp->f_type == arg)) {
@@ -1339,14 +1333,7 @@ sysctl_file(int *name, u_int namelen, ch
if (!skip)
FILLIT(fp, NULL, 0, NULL, NULL);
}
- nfp = LIST_NEXT(fp, f_list);
- while (nfp != NULL && nfp->f_count == 0)
- nfp = LIST_NEXT(nfp, f_list);
- if (nfp != NULL)
- FREF(nfp);
- FRELE(fp, p);
- fp = nfp;
- } while (fp != NULL);
+ };
break;
case KERN_FILE_BYPID:
/* A arg of -1 indicates all processes */
Index: sys/file.h
===================================================================
RCS file: /cvs/src/sys/sys/file.h,v
retrieving revision 1.40
diff -u -p -r1.40 file.h
--- sys/file.h 10 Feb 2018 05:24:23 -0000 1.40
+++ sys/file.h 16 Apr 2018 12:43:19 -0000
@@ -106,7 +106,6 @@ struct file {
int fdrop(struct file *, struct proc *);
LIST_HEAD(filelist, file);
-extern struct filelist filehead; /* head of list of open files */
extern int maxfiles; /* kernel limit on number of open files
*/
extern int numfiles; /* actual number of open files */
extern struct fileops vnops; /* vnode operations for files */
Index: sys/filedesc.h
===================================================================
RCS file: /cvs/src/sys/sys/filedesc.h,v
retrieving revision 1.34
diff -u -p -r1.34 filedesc.h
--- sys/filedesc.h 11 Feb 2017 19:51:06 -0000 1.34
+++ sys/filedesc.h 16 Apr 2018 12:43:19 -0000
@@ -133,6 +133,7 @@ void fdfree(struct proc *p);
int fdrelease(struct proc *p, int);
void fdremove(struct filedesc *, int);
void fdcloseexec(struct proc *);
+struct file *fd_iterfile(struct file *, struct proc *);
struct file *fd_getfile(struct filedesc *, int);
struct file *fd_getfile_mode(struct filedesc *, int, int);