Unmap pages mapped during a failed fill_vmr()
[akaros.git] / kern / drivers / dev / tmpfs.c
1 /* Copyright (c) 2018 Google Inc
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * #tmpfs, in-memory ram filesystem instance.
6  *
7  * Compared to #kfs, there can be many #tmpfs instances, all of which are
8  * independent and clean themeselves up when they are detached and the last chan
9  * is closed.  A few notes:
10  * - The FS root ("/") can't be removed.  When you unmount, it gets
11  *   closed/decreffed.
12  * - The tmpfs will exist for the life of any open chans, including the mount.
13  *   You can e.g. cd into a subdir, unmount /, and the tmpfs will stay alive til
14  *   you leave the directory (basically close the chan).  You can do the same
15  *   thing with open_at().
16  * - The root tree_file will not be deleted so long as you have an open chan.
17  *   Any open chan on a subdir/subfile will hold refs on the root.  The mount
18  *   point will also hold those refs.  We also hold an additional +1 on the root
19  *   TF, which we drop once we have no users and we've purged the tree. */
20
21 #include <ns.h>
22 #include <kmalloc.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <error.h>
27 #include <tree_file.h>
28 #include <pmap.h>
29 #include <cpio.h>
30
31 struct dev tmpfs_devtab;
32
33 /* This is a little wasteful - a u16_pool will work too, though I'd like to
34  * exercise bits of the arena code. */
35 static struct arena *tmpfs_ids;
36
37 struct tmpfs {
38         struct tree_filesystem          tfs;
39         atomic_t                        qid_file;
40         uint16_t                        id;
41         struct kref                     users;
42 };
43
44 static struct tmpfs *tree_file_to_tmpfs(struct tree_file *tf)
45 {
46         return (struct tmpfs*)(tf->tfs);
47 }
48
49 #define TMPFS_MAX_QID_FILE ((1ULL << 48) - 1)
50 #define TMPFS_MAX_ID ((1 << 16) - 1)
51
52 /* Qids are made up of 16 bits for the ID, 48 for the file. */
53 static uint64_t tmpfs_get_qid_path(struct tmpfs *tmpfs)
54 {
55         uint64_t ret = atomic_fetch_and_add(&tmpfs->qid_file, 1);
56
57         /* Wrap-around of qid_file won't happen in our lifetime */
58         if (ret > TMPFS_MAX_QID_FILE)
59                 error(ENOSPC, "out of tmpfs files");
60         return ((uint64_t)tmpfs->id << 16) | ret;
61 }
62
63 static char *devname(void)
64 {
65         return tmpfs_devtab.name;
66 }
67
68 static void tmpfs_tf_free(struct tree_file *tf)
69 {
70         /* We have nothing special hanging off the TF */
71 }
72
73 static void tmpfs_tf_unlink(struct tree_file *parent, struct tree_file *child)
74 {
75         /* This is the "+1 for existing" ref. */
76         tf_kref_put(child);
77 }
78
79 static void __tmpfs_tf_init(struct tree_file *tf, int dir_type, int dir_dev,
80                             struct username *user, int perm)
81 {
82         struct dir *dir = &tf->file.dir;
83
84         fs_file_init_dir(&tf->file, dir_type, dir_dev, user, perm);
85         dir->qid.path = tmpfs_get_qid_path(tree_file_to_tmpfs(tf));
86         dir->qid.vers = 0;
87         /* This is the "+1 for existing" ref.  There is no backing store for the
88          * FS, such as a disk or 9p, so we can't get rid of a file until it is
89          * unlinked and decreffed.  Note that KFS doesn't use pruners or
90          * anything else. */
91         __kref_get(&tf->kref, 1);
92 }
93
94 /* Note: If your TFS doesn't support symlinks, you need to error out */
95 static void tmpfs_tf_create(struct tree_file *parent, struct tree_file *child,
96                             int perm)
97 {
98         __tmpfs_tf_init(child, parent->file.dir.type, parent->file.dir.dev,
99                         &eve, perm);
100 }
101
102 static void tmpfs_tf_rename(struct tree_file *tf, struct tree_file *old_parent,
103                             struct tree_file *new_parent, const char *name,
104                             int flags)
105 {
106         /* We don't have a backend, so we don't need to do anything additional
107          * for rename. */
108 }
109
110 static bool tmpfs_tf_has_children(struct tree_file *parent)
111 {
112         /* The tree_file parent list is complete and not merely a cache for a
113          * real backend. */
114         return !list_empty(&parent->children);
115 }
116
117 struct tree_file_ops tmpfs_tf_ops = {
118         .free = tmpfs_tf_free,
119         .unlink = tmpfs_tf_unlink,
120         .lookup = NULL,
121         .create = tmpfs_tf_create,
122         .rename = tmpfs_tf_rename,
123         .has_children = tmpfs_tf_has_children,
124 };
125
126 /* Fills page with its contents from its backing store file.  For KFS, that
127  * means we're creating or extending a file, and the contents are 0.  Note the
128  * page/offset might be beyond the current file length, based on the current
129  * pagemap code. */
130 static int tmpfs_pm_readpage(struct page_map *pm, struct page *pg)
131 {
132         memset(page2kva(pg), 0, PGSIZE);
133         atomic_or(&pg->pg_flags, PG_UPTODATE);
134         /* Pretend that we blocked while filing this page.  This catches a lot
135          * of bugs.  It does slightly slow down the kernel, but it's only when
136          * filling the page cache, and considering we are using a RAMFS, you
137          * shouldn't measure things that actually rely on KFS's performance. */
138         kthread_usleep(1);
139         return 0;
140 }
141
142 /* Meant to take the page from PM and flush to backing store.  There is no
143  * backing store. */
144 static int tmpfs_pm_writepage(struct page_map *pm, struct page *pg)
145 {
146         return 0;
147 }
148
149 static void tmpfs_fs_punch_hole(struct fs_file *f, off64_t begin, off64_t end)
150 {
151 }
152
153 static bool tmpfs_fs_can_grow_to(struct fs_file *f, size_t len)
154 {
155         /* TODO: implement some sort of memory limit */
156         return true;
157 }
158
159 struct fs_file_ops tmpfs_fs_ops = {
160         .readpage = tmpfs_pm_readpage,
161         .writepage = tmpfs_pm_writepage,
162         .punch_hole = tmpfs_fs_punch_hole,
163         .can_grow_to = tmpfs_fs_can_grow_to,
164 };
165
166 static void purge_cb(struct tree_file *tf)
167 {
168         /* this is the +1 for existing */
169         tf_kref_put(tf);
170 }
171
172 static void tmpfs_release(struct kref *kref)
173 {
174         struct tmpfs *tmpfs = container_of(kref, struct tmpfs, users);
175
176         tfs_frontend_purge(&tmpfs->tfs, purge_cb);
177         /* this is the ref from attach */
178         assert(kref_refcnt(&tmpfs->tfs.root->kref) == 1);
179         tf_kref_put(tmpfs->tfs.root);
180         /* ensures __tf_free() happens before tfs_destroy */
181         rcu_barrier();
182         tfs_destroy(&tmpfs->tfs);
183         arena_free(tmpfs_ids, (void*)(uintptr_t)tmpfs->id, 1);
184         kfree(tmpfs);
185 }
186
187 static struct tmpfs *chan_to_tmpfs(struct chan *c)
188 {
189         return tree_file_to_tmpfs(chan_to_tree_file(c));
190 }
191
192 static void incref_tmpfs_chan(struct chan *c)
193 {
194         kref_get(&chan_to_tmpfs(c)->users, 1);
195 }
196
197 static void decref_tmpfs_chan(struct chan *c)
198 {
199         kref_put(&chan_to_tmpfs(c)->users);
200 }
201
202 static void tmpfs_reset(void)
203 {
204         /* Note you can't make an arena that hands out '0'.  That's baked into
205          * the interface.  I'm OK with it for now.  Because of that, the *size*
206          * of the span is 2^16 - 1; can't count '0'. */
207         tmpfs_ids = arena_create("tmpfs_ids", (void*)1, TMPFS_MAX_ID, 1,
208                                  NULL, NULL, NULL, 0, ARENA_NEXTFIT | MEM_WAIT);
209 }
210
211 /* This is pretty hokey - we never call shutdown, and I don't know if 9ns has
212  * any protections about device use before calling shutdown. */
213 static void tmpfs_shutdown(void)
214 {
215         arena_destroy(tmpfs_ids);
216         tmpfs_ids = NULL;
217 }
218
219 static struct chan *tmpfs_attach(char *spec)
220 {
221         struct tree_filesystem *tfs = kzmalloc(sizeof(struct tmpfs), MEM_WAIT);
222         struct tmpfs *tmpfs = (struct tmpfs*)tfs;
223
224         /* All distinct chans get a ref on the filesystem, so that we can
225          * destroy it when the last user disconnects/closes. */
226         kref_init(&tmpfs->users, tmpfs_release, 1);
227         tmpfs->id = (uint16_t)(uintptr_t)arena_alloc(tmpfs_ids, 1, MEM_WAIT);
228
229         /* This gives us one ref on root, dropped during tmpfs_release(). */
230         tfs_init(tfs);
231         tfs->tf_ops = tmpfs_tf_ops;
232         tfs->fs_ops = tmpfs_fs_ops;
233
234         /* This gives us an extra refcnt on tfs->root.  This is "+1 for
235          * existing." It is decreffed during the purge CB. */
236         __tmpfs_tf_init(tfs->root, &tmpfs_devtab - devtab, 0, &eve, DMDIR |
237                         0777);
238         /* This also increfs, copying tfs->root's ref for the chan it returns.*/
239         return tree_file_alloc_chan(tfs->root, &tmpfs_devtab, "#tmpfs");
240 }
241
242 static struct walkqid *tmpfs_walk(struct chan *c, struct chan *nc, char **name,
243                                   unsigned int nname)
244 {
245         struct walkqid *wq = tree_chan_walk(c, nc, name, nname);
246
247         if (wq && wq->clone && (wq->clone != c))
248                 incref_tmpfs_chan(wq->clone);
249         return wq;
250 }
251
252 static void tmpfs_close(struct chan *c)
253 {
254         tree_chan_close(c);
255         decref_tmpfs_chan(c);
256 }
257
258 static void tmpfs_remove(struct chan *c)
259 {
260         ERRSTACK(1);
261         struct tmpfs *tmpfs = chan_to_tmpfs(c);
262
263         /* This is a bit of a pain - when remove fails, we won't get a chance to
264          * close the chan.  See notes in tree_chan_remove() and sysremove(). */
265         if (waserror()) {
266                 kref_put(&tmpfs->users);
267                 nexterror();
268         }
269         tree_chan_remove(c);
270         kref_put(&tmpfs->users);
271         poperror();
272 }
273
274 void tmpfs_rename(struct chan *c, struct chan *new_p_c, const char *name,
275                   int flags)
276 {
277         struct tmpfs *tmpfs_old = chan_to_tmpfs(c);
278         struct tmpfs *tmpfs_new = chan_to_tmpfs(new_p_c);
279
280         /* namec checked that both were from the same device.  It is our
281          * responsibility to make sure they are the same version. */
282         if (tmpfs_old != tmpfs_new)
283                 error(EXDEV, "can't rename across tmpfs instances");
284         tree_chan_rename(c, new_p_c, name, flags);
285 }
286
287 static unsigned long tmpfs_chan_ctl(struct chan *c, int op, unsigned long a1,
288                                     unsigned long a2, unsigned long a3,
289                                     unsigned long a4)
290 {
291         switch (op) {
292         case CCTL_SYNC:
293                 return 0;
294         default:
295                 return tree_chan_ctl(c, op, a1, a2, a3, a4);
296         }
297 }
298
299 struct dev tmpfs_devtab __devtab = {
300         .name = "tmpfs",
301         .reset = tmpfs_reset,
302         .init = devinit,
303         .shutdown = tmpfs_shutdown,
304         .attach = tmpfs_attach,
305         .walk = tmpfs_walk,
306         .stat = tree_chan_stat,
307         .open = tree_chan_open,
308         .create = tree_chan_create,
309         .close = tmpfs_close,
310         .read = tree_chan_read,
311         .bread = devbread,
312         .write = tree_chan_write,
313         .bwrite = devbwrite,
314         .remove = tmpfs_remove,
315         .rename = tmpfs_rename,
316         .wstat = tree_chan_wstat,
317         .power = devpower,
318         .chaninfo = devchaninfo,
319         .mmap = tree_chan_mmap,
320         .chan_ctl = tmpfs_chan_ctl,
321 };