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