1*433d6423SLionel Sambuc
2*433d6423SLionel Sambuc /* File that implements the 'fdref' data structure. It keeps track
3*433d6423SLionel Sambuc * of how many times a particular fd (per process) is referenced by
4*433d6423SLionel Sambuc * mmapped objects.
5*433d6423SLionel Sambuc *
6*433d6423SLionel Sambuc * This is used to
7*433d6423SLionel Sambuc * - have many references to the same file, without needing an FD each
8*433d6423SLionel Sambuc * - deciding when we have to close an FD (last reference disappears)
9*433d6423SLionel Sambuc *
10*433d6423SLionel Sambuc * Examples:
11*433d6423SLionel Sambuc * - if a file-mmapped region is split, the refcount increases; there are
12*433d6423SLionel Sambuc * now two regions referencing the same FD. We can't simply close the
13*433d6423SLionel Sambuc * FD once either region is unmapped, as the pagefaults for the other
14*433d6423SLionel Sambuc * would stop working. So we increase the refcount to that fd.
15*433d6423SLionel Sambuc * - if a new file-maped region is requested, we might find out it's the
16*433d6423SLionel Sambuc * same dev/inode the same process already has referenced. we could
17*433d6423SLionel Sambuc * decide to close the new reference and use an existing one, so
18*433d6423SLionel Sambuc * references to the same file aren't fd-limited.
19*433d6423SLionel Sambuc * - if a file-mapped region is copied, we have to create a new
20*433d6423SLionel Sambuc * fdref object, as the source process might disappear; we have to
21*433d6423SLionel Sambuc * use the new process' fd for it.
22*433d6423SLionel Sambuc */
23*433d6423SLionel Sambuc
24*433d6423SLionel Sambuc #include <assert.h>
25*433d6423SLionel Sambuc #include <string.h>
26*433d6423SLionel Sambuc
27*433d6423SLionel Sambuc #include <minix/hash.h>
28*433d6423SLionel Sambuc
29*433d6423SLionel Sambuc #include "proto.h"
30*433d6423SLionel Sambuc #include "vm.h"
31*433d6423SLionel Sambuc #include "fdref.h"
32*433d6423SLionel Sambuc #include "vmproc.h"
33*433d6423SLionel Sambuc #include "glo.h"
34*433d6423SLionel Sambuc
35*433d6423SLionel Sambuc static struct fdref *fdrefs;
36*433d6423SLionel Sambuc
fdref_sanitycheck(void)37*433d6423SLionel Sambuc void fdref_sanitycheck(void)
38*433d6423SLionel Sambuc {
39*433d6423SLionel Sambuc struct vmproc *vmp;
40*433d6423SLionel Sambuc region_iter v_iter;
41*433d6423SLionel Sambuc struct fdref *fr;
42*433d6423SLionel Sambuc static int prevopen = 0;
43*433d6423SLionel Sambuc int openfd = 0;
44*433d6423SLionel Sambuc
45*433d6423SLionel Sambuc for(fr = fdrefs; fr; fr = fr->next) {
46*433d6423SLionel Sambuc struct fdref *fr2;
47*433d6423SLionel Sambuc for(fr2 = fdrefs; fr2; fr2 = fr2->next) {
48*433d6423SLionel Sambuc if(fr == fr2) continue;
49*433d6423SLionel Sambuc if(fr->fd == fr2->fd) {
50*433d6423SLionel Sambuc printf("equal fd omg\n");
51*433d6423SLionel Sambuc util_stacktrace();
52*433d6423SLionel Sambuc }
53*433d6423SLionel Sambuc if(fr->ino == fr2->ino && fr->dev == fr2->dev) {
54*433d6423SLionel Sambuc printf("equal metadata omg\n");
55*433d6423SLionel Sambuc util_stacktrace();
56*433d6423SLionel Sambuc }
57*433d6423SLionel Sambuc }
58*433d6423SLionel Sambuc openfd++;
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc
61*433d6423SLionel Sambuc for(fr = fdrefs; fr; fr = fr->next) {
62*433d6423SLionel Sambuc fr->counting = 0;
63*433d6423SLionel Sambuc }
64*433d6423SLionel Sambuc
65*433d6423SLionel Sambuc for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) {
66*433d6423SLionel Sambuc struct vir_region *vr;
67*433d6423SLionel Sambuc if(!(vmp->vm_flags & VMF_INUSE))
68*433d6423SLionel Sambuc continue;
69*433d6423SLionel Sambuc region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
70*433d6423SLionel Sambuc while((vr = region_get_iter(&v_iter))) {
71*433d6423SLionel Sambuc if(vr->def_memtype == &mem_type_mappedfile && vr->param.file.inited) {
72*433d6423SLionel Sambuc vr->param.file.fdref->counting++;
73*433d6423SLionel Sambuc }
74*433d6423SLionel Sambuc region_incr_iter(&v_iter);
75*433d6423SLionel Sambuc }
76*433d6423SLionel Sambuc
77*433d6423SLionel Sambuc }
78*433d6423SLionel Sambuc
79*433d6423SLionel Sambuc for(fr = fdrefs; fr; fr = fr->next) {
80*433d6423SLionel Sambuc if(fr->counting != fr->refcount) {
81*433d6423SLionel Sambuc printf("counting %d != refcount %d\n",
82*433d6423SLionel Sambuc fr->counting, fr->refcount);
83*433d6423SLionel Sambuc util_stacktrace();
84*433d6423SLionel Sambuc }
85*433d6423SLionel Sambuc }
86*433d6423SLionel Sambuc
87*433d6423SLionel Sambuc if(prevopen != openfd && openfd > 100) {
88*433d6423SLionel Sambuc printf("%d open\n", openfd);
89*433d6423SLionel Sambuc prevopen = openfd;
90*433d6423SLionel Sambuc }
91*433d6423SLionel Sambuc }
92*433d6423SLionel Sambuc
fdref_new(struct vmproc * owner,ino_t ino,dev_t dev,int fd)93*433d6423SLionel Sambuc struct fdref *fdref_new(struct vmproc *owner, ino_t ino, dev_t dev, int fd)
94*433d6423SLionel Sambuc {
95*433d6423SLionel Sambuc struct fdref *nfdref;
96*433d6423SLionel Sambuc
97*433d6423SLionel Sambuc if(!SLABALLOC(nfdref)) return NULL;
98*433d6423SLionel Sambuc
99*433d6423SLionel Sambuc nfdref->fd = fd;
100*433d6423SLionel Sambuc nfdref->refcount = 0;
101*433d6423SLionel Sambuc nfdref->dev = dev;
102*433d6423SLionel Sambuc nfdref->ino = ino;
103*433d6423SLionel Sambuc nfdref->next = fdrefs;
104*433d6423SLionel Sambuc fdrefs = nfdref;
105*433d6423SLionel Sambuc
106*433d6423SLionel Sambuc return nfdref;
107*433d6423SLionel Sambuc }
108*433d6423SLionel Sambuc
fdref_ref(struct fdref * ref,struct vir_region * region)109*433d6423SLionel Sambuc void fdref_ref(struct fdref *ref, struct vir_region *region)
110*433d6423SLionel Sambuc {
111*433d6423SLionel Sambuc assert(ref);
112*433d6423SLionel Sambuc region->param.file.fdref = ref;
113*433d6423SLionel Sambuc ref->refcount++;
114*433d6423SLionel Sambuc }
115*433d6423SLionel Sambuc
fdref_deref(struct vir_region * region)116*433d6423SLionel Sambuc void fdref_deref(struct vir_region *region)
117*433d6423SLionel Sambuc {
118*433d6423SLionel Sambuc struct fdref *ref = region->param.file.fdref;
119*433d6423SLionel Sambuc int fd;
120*433d6423SLionel Sambuc
121*433d6423SLionel Sambuc assert(ref);
122*433d6423SLionel Sambuc assert(ref->refcount > 0);
123*433d6423SLionel Sambuc
124*433d6423SLionel Sambuc fd = ref->fd;
125*433d6423SLionel Sambuc region->param.file.fdref = NULL;
126*433d6423SLionel Sambuc ref->refcount--;
127*433d6423SLionel Sambuc assert(ref->refcount >= 0);
128*433d6423SLionel Sambuc if(ref->refcount > 0) return;
129*433d6423SLionel Sambuc
130*433d6423SLionel Sambuc if(fdrefs == ref) fdrefs = ref->next;
131*433d6423SLionel Sambuc else {
132*433d6423SLionel Sambuc struct fdref *r;
133*433d6423SLionel Sambuc for(r = fdrefs; r->next != ref; r = r->next)
134*433d6423SLionel Sambuc ;
135*433d6423SLionel Sambuc assert(r);
136*433d6423SLionel Sambuc assert(r->next == ref);
137*433d6423SLionel Sambuc r->next = ref->next;
138*433d6423SLionel Sambuc }
139*433d6423SLionel Sambuc
140*433d6423SLionel Sambuc SLABFREE(ref);
141*433d6423SLionel Sambuc ref = NULL;
142*433d6423SLionel Sambuc
143*433d6423SLionel Sambuc /* If the last reference has disappeared, free the
144*433d6423SLionel Sambuc * ref object and asynchronously close the fd in VFS.
145*433d6423SLionel Sambuc *
146*433d6423SLionel Sambuc * We don't need a callback as a close failing, although
147*433d6423SLionel Sambuc * unexpected, isn't a problem and can't be handled. VFS
148*433d6423SLionel Sambuc * will print a diagnostic.
149*433d6423SLionel Sambuc */
150*433d6423SLionel Sambuc if(vfs_request(VMVFSREQ_FDCLOSE, fd, region->parent,
151*433d6423SLionel Sambuc 0, 0, NULL, NULL, NULL, 0) != OK) {
152*433d6423SLionel Sambuc panic("fdref_deref: could not send close request");
153*433d6423SLionel Sambuc }
154*433d6423SLionel Sambuc }
155*433d6423SLionel Sambuc
fdref_dedup_or_new(struct vmproc * owner,ino_t ino,dev_t dev,int fd,int mayclose)156*433d6423SLionel Sambuc struct fdref *fdref_dedup_or_new(struct vmproc *owner,
157*433d6423SLionel Sambuc ino_t ino, dev_t dev, int fd, int mayclose)
158*433d6423SLionel Sambuc {
159*433d6423SLionel Sambuc struct fdref *fr;
160*433d6423SLionel Sambuc
161*433d6423SLionel Sambuc for(fr = fdrefs; fr; fr = fr->next) {
162*433d6423SLionel Sambuc if(ino == fr->ino && dev == fr->dev) {
163*433d6423SLionel Sambuc if(fd == fr->fd) {
164*433d6423SLionel Sambuc return fr;
165*433d6423SLionel Sambuc }
166*433d6423SLionel Sambuc if(!mayclose) continue;
167*433d6423SLionel Sambuc if(vfs_request(VMVFSREQ_FDCLOSE, fd, owner,
168*433d6423SLionel Sambuc 0, 0, NULL, NULL, NULL, 0) != OK) {
169*433d6423SLionel Sambuc printf("fdref_dedup_or_new: could not close\n");
170*433d6423SLionel Sambuc }
171*433d6423SLionel Sambuc return fr;
172*433d6423SLionel Sambuc }
173*433d6423SLionel Sambuc }
174*433d6423SLionel Sambuc
175*433d6423SLionel Sambuc return fdref_new(owner, ino, dev, fd);
176*433d6423SLionel Sambuc }
177*433d6423SLionel Sambuc
178