9ns: Add fs_files and tree_files
[akaros.git] / kern / src / ns / fs_file.c
1 /* Copyright (c) 2018 Google Inc
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * fs_file: structs and helpers for files for 9ns devices
6  */
7
8 #include <fs_file.h>
9 #include <kmalloc.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <assert.h>
13 #include <error.h>
14 #include <umem.h>
15 #include <pmap.h>
16
17 /* Initializes a zalloced fs_file.  The caller is responsible for filling in
18  * dir, except for name.  Most fields are fine with being zeroed.  Note the kref
19  * == 0 too. */
20 void fs_file_init(struct fs_file *f, const char *name, struct fs_file_ops *ops)
21 {
22         qlock_init(&f->qlock);
23         fs_file_set_basename(f, name);
24         f->ops = ops;
25         /* TODO: consider holding off on initializing the PM, since only walked and
26          * opened entries could use it.  pm == NULL means no PM yet.  Negative
27          * entries will never be used in this manner.  Doing it now avoids races,
28          * though it's mostly zeroing cache-hot fields. */
29         f->pm = &f->static_pm;
30         pm_init(f->pm, (struct page_map_operations*)ops, f);
31 }
32
33 void fs_file_set_basename(struct fs_file *f, const char *name)
34 {
35         size_t name_len = strlen(name) + 1;
36
37         if (name_len > KNAMELEN)
38                 f->dir.name = kzmalloc(name_len, MEM_WAIT);
39         else
40                 f->dir.name = f->static_name;
41         memcpy(f->dir.name, name, name_len);
42 }
43
44 /* Technically, a reader could see the old string pointer and read it.  That
45  * memory could be realloced and used for something else.  But thanks to the
46  * seqctr, the reader will retry.  Otherwise, we might not need the seqctr,
47  * since we never change_basename when a file is in a tree.  So far.
48  *
49  * The only reader that races with setting the name is stat.  Regular lookups
50  * won't see the file, since it was removed from the HT, and readdirs won't see
51  * it due to the parent's qlock. */
52 void fs_file_change_basename(struct fs_file *f, const char *name)
53 {
54         char *old_name = NULL;
55         char *new_name = NULL;
56         size_t name_len = strlen(name) + 1;
57
58         if (name_len > KNAMELEN)
59                 new_name = kzmalloc(name_len, MEM_WAIT);
60         qlock(&f->qlock);
61         if (f->dir.name != f->static_name)
62                 old_name = f->dir.name;
63         if (new_name)
64                 f->dir.name = new_name;
65         else
66                 f->dir.name = f->static_name;
67         memcpy(f->dir.name, name, name_len);
68         /* TODO: if we store the hash of the name in the file, do so here. */
69         qunlock(&f->qlock);
70         kfree(old_name);
71 }
72
73 /* Helper for building a dir.  Caller sets qid path and vers.  YMMV. */
74 void fs_file_init_dir(struct fs_file *f, int dir_type, int dir_dev,
75                       struct username *user, int perm)
76 {
77         struct dir *dir = &f->dir;
78
79         if (perm & DMDIR)
80                 dir->qid.type |= QTDIR;
81         if (perm & DMAPPEND)
82                 dir->qid.type |= QTAPPEND;
83         if (perm & DMEXCL)
84                 dir->qid.type |= QTEXCL;
85         if (perm & DMSYMLINK)
86                 dir->qid.type |= QTSYMLINK;
87         if (!(dir->qid.type & (QTSYMLINK | QTDIR)))
88                 dir->qid.type |= QTFILE;
89         dir->mode = perm;
90         __set_acmtime(f, FSF_ATIME | FSF_BTIME | FSF_MTIME | FSF_CTIME);
91         dir->length = 0;
92         /* TODO: this is a mess if you use anything other than eve.  If you use a
93          * process, that memory is sitting in the proc struct, but we have weak refs
94          * on it.  What happens when that proc exits?  Disaster. */
95         assert(user == &eve);
96         dir->uid = user->name;
97         dir->gid = user->name;
98         dir->muid = user->name;
99 }
100
101 static char *copy_str(const char *s)
102 {
103         char *ret;
104         size_t sz;
105
106         if (!s)
107                 return NULL;
108         sz = strlen(s) + 1;
109         ret = kmalloc(sz, MEM_WAIT);
110         memcpy(ret, s, sz);
111         return ret;
112 }
113
114 /* Deep copies the contents of dir into the fs_file's dir. */
115 void fs_file_copy_from_dir(struct fs_file *f, struct dir *dir)
116 {
117         memcpy(&f->dir, dir, sizeof(struct dir));
118         fs_file_set_basename(f, dir->name);
119         /* TODO: sort out usernames.  Not only are these just eve, but they are not
120          * struct user or something and they ignore whatever the name was from the
121          * remote end. */
122         f->dir.uid = eve.name;
123         f->dir.gid = eve.name;
124         f->dir.muid = eve.name;
125         f->dir.ext = copy_str(dir->ext);
126 }
127
128 void cleanup_fs_file(struct fs_file *f)
129 {
130         if (f->dir.name != f->static_name)
131                 kfree(f->dir.name);
132         /* TODO: Not sure if these will be refcounted objects in the future.  Keep
133          * this in sync with other code that manages/sets uid/gid/muid. */
134         f->dir.uid = NULL;
135         f->dir.gid = NULL;
136         f->dir.muid = NULL;
137         if (f->dir.ext)
138                 kfree(f->dir.ext);
139         f->dir.ext = NULL;
140         pm_destroy(f->pm);
141         /* Might share mappings in the future.  Catch it here. */
142         assert(f->pm == &f->static_pm);
143 }
144
145 void __set_acmtime_to(struct fs_file *f, int which, struct timespec *t)
146 {
147         /* WRITE_ONCE, due to lockless peakers */
148         if (which & FSF_ATIME) {
149                 WRITE_ONCE(f->dir.atime.tv_sec, t->tv_sec);
150                 WRITE_ONCE(f->dir.atime.tv_nsec, t->tv_nsec);
151         }
152         if (which & FSF_BTIME) {
153                 WRITE_ONCE(f->dir.btime.tv_sec, t->tv_sec);
154                 WRITE_ONCE(f->dir.btime.tv_nsec, t->tv_nsec);
155         }
156         if (which & FSF_CTIME) {
157                 WRITE_ONCE(f->dir.ctime.tv_sec, t->tv_sec);
158                 WRITE_ONCE(f->dir.ctime.tv_nsec, t->tv_nsec);
159         }
160         if (which & FSF_MTIME) {
161                 WRITE_ONCE(f->dir.mtime.tv_sec, t->tv_sec);
162                 WRITE_ONCE(f->dir.mtime.tv_nsec, t->tv_nsec);
163         }
164 }
165
166 /* Caller should hold f's qlock */
167 void __set_acmtime(struct fs_file *f, int which)
168 {
169         struct timespec now = nsec2timespec(epoch_nsec());
170
171         __set_acmtime_to(f, which, &now);
172 }
173
174 /* Recall that the frontend always has the most up-to-date info.  This gets
175  * synced to the backend when we flush or fsync. */
176 void set_acmtime_to(struct fs_file *f, int which, struct timespec *t)
177 {
178         ERRSTACK(1);
179
180         qlock(&f->qlock);
181         if (waserror()) {
182                 qunlock(&f->qlock);
183                 nexterror();
184         }
185         if ((which & FSF_ATIME) && !caller_has_file_perms(f, O_READ))
186                 error(EPERM, "insufficient perms to set atime");
187         if ((which & FSF_BTIME) && !caller_is_username(f->dir.uid))
188                 error(EPERM, "insufficient perms to set btime");
189         if ((which & FSF_CTIME) && !caller_has_file_perms(f, O_WRITE))
190                 error(EPERM, "insufficient perms to set ctime");
191         if ((which & FSF_MTIME) && !caller_has_file_perms(f, O_WRITE))
192                 error(EPERM, "insufficient perms to set mtime");
193         __set_acmtime_to(f, which, t);
194         qunlock(&f->qlock);
195         poperror();
196 }
197
198 void set_acmtime_noperm(struct fs_file *f, int which)
199 {
200         struct timespec now = nsec2timespec(epoch_nsec());
201
202         /* <3 atime.  We'll go with an hour resolution, like NTFS. */
203         if (which == FSF_ATIME) {
204                 if (now.tv_sec < ACCESS_ONCE(f->dir.atime.tv_sec) + 3600)
205                         return;
206         }
207         qlock(&f->qlock);
208         __set_acmtime_to(f, which, &now);
209         qunlock(&f->qlock);
210 }
211
212 size_t fs_file_stat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz)
213 {
214         size_t ret;
215
216         qlock(&f->qlock);
217         ret = convD2M(&f->dir, m_buf, m_buf_sz);
218         qunlock(&f->qlock);
219         if (ret <= BIT16SZ)
220                 error(EINVAL, "buffer too small for stat");
221         return ret;
222 }
223
224 /* Punches a hole from begin to end.  Pages completely in the hole will be
225  * removed.  Otherwise, the edges will be zeroed.  Caller holds the qlock. */
226 static void __fs_file_punch_hole(struct fs_file *f, off64_t begin, off64_t end)
227 {
228         size_t first_pg_idx, last_pg_idx, nr_pages, zero_amt;
229         struct page *page;
230         int error;
231
232         /* Caller should check for this */
233         assert((long)begin >= 0);
234         assert((long)end >= 0);
235         end = MIN(end, f->dir.length);
236         if (end <= begin)
237                 return;
238         first_pg_idx = LA2PPN(begin);
239         last_pg_idx = LA2PPN(end);
240         nr_pages = last_pg_idx - first_pg_idx + 1;
241         if (PGOFF(begin)) {
242                 error = pm_load_page(f->pm, first_pg_idx, &page);
243                 if (error)
244                         error(-error, "punch_hole pm_load_page failed");
245                 zero_amt = MIN(PGSIZE - PGOFF(begin), end - begin);
246                 memset(page2kva(page) + PGOFF(begin), 0, zero_amt);
247                 atomic_or(&page->pg_flags, PG_DIRTY);
248                 pm_put_page(page);
249                 first_pg_idx--;
250                 nr_pages--;
251                 if (!nr_pages)
252                         return;
253         }
254         if (PGOFF(end) && (end < f->dir.length)) {
255                 error = pm_load_page(f->pm, last_pg_idx, &page);
256                 if (error)
257                         error(-error, "punch_hole pm_load_page failed");
258                 memset(page2kva(page), 0, PGOFF(end));
259                 atomic_or(&page->pg_flags, PG_DIRTY);
260                 pm_put_page(page);
261                 nr_pages--;
262                 if (!nr_pages)
263                         return;
264         }
265         /* We hold the qlock, so new pages won't get loaded (load_nowait will fail).
266          * However, this won't remove all pages yet! (see PM comments above) */
267         pm_remove_contig(f->pm, first_pg_idx, nr_pages);
268         /* Need to do an FS op to immediately tell the backing store before we read
269          * a page back in to the PM.  Otherwise, we might see old data.  Consider a
270          * truncate to 0, then back to len. */
271         f->ops->punch_hole(f, begin, end);
272 }
273
274 void fs_file_truncate(struct fs_file *f, off64_t to)
275 {
276         ERRSTACK(1);
277
278         fs_file_perm_check(f, O_WRITE);
279         qlock(&f->qlock);
280         if (waserror()) {
281                 qunlock(&f->qlock);
282                 nexterror();
283         }
284         if (to < f->dir.length) {
285                 __fs_file_punch_hole(f, to, f->dir.length);
286         } else {
287                 if (!f->ops->can_grow_to(f, to))
288                         error(EINVAL, "can't grow file to %lu bytes", to);
289         }
290         WRITE_ONCE(f->dir.length, to);
291         __set_acmtime(f, FSF_MTIME | FSF_CTIME);
292         qunlock(&f->qlock);
293         poperror();
294 }
295
296 /* This attempts to avoid the file qlock when pages are in the page cache.
297  *
298  * If we want to go simpler and use the qlock, always check len, don't use
299  * _nowait, it's not a 'lockless peak', write can set the len at the top, and
300  * all writes to dir.length can be normal. */
301 size_t fs_file_read(struct fs_file *f, uint8_t *buf, size_t count,
302                     off64_t offset)
303 {
304         ERRSTACK(1);
305         struct page *page;
306         size_t copy_amt, pg_off, pg_idx, total_remaining;
307         volatile size_t so_far = 0;             /* volatile for waserror */
308         const uint8_t *buf_end = buf + count;
309         int error;
310
311         if (waserror()) {
312                 if (so_far) {
313                         poperror();
314                         return so_far;
315                 }
316                 nexterror();
317         }
318         while (buf < buf_end) {
319                 pg_off = PGOFF(offset + so_far);
320                 pg_idx = LA2PPN(offset + so_far);
321                 error = pm_load_page_nowait(f->pm, pg_idx, &page);
322                 if (error == -EAGAIN) {
323                         qlock(&f->qlock);
324                         /* Don't attempt to load pages beyond len.  The rest of the read
325                          * code can handle it (it won't copy), but the backend FS might get
326                          * confused. */
327                         if (f->dir.length <= offset + so_far) {
328                                 qunlock(&f->qlock);
329                                 break;
330                         }
331                         error = pm_load_page(f->pm, pg_idx, &page);
332                         qunlock(&f->qlock);
333                 }
334                 if (error)
335                         error(-error, "read pm_load_page failed");
336                 copy_amt = MIN(PGSIZE - pg_off, buf_end - buf);
337                 /* Lockless peak.  Check the len so we don't read beyond EOF.  We have a
338                  * page, but we don't necessarily have access to all of it. */
339                 total_remaining = ACCESS_ONCE(f->dir.length) - (offset + so_far);
340                 if (copy_amt > total_remaining) {
341                         copy_amt = total_remaining;
342                         buf_end = buf + copy_amt;
343                 }
344                 memcpy_to_safe(buf, page2kva(page) + pg_off, copy_amt);
345                 buf += copy_amt;
346                 so_far += copy_amt;
347                 pm_put_page(page);
348         }
349         if (so_far)
350                 set_acmtime_noperm(f, FSF_ATIME);
351         poperror();
352         return so_far;
353 }
354
355 size_t fs_file_write(struct fs_file *f, const uint8_t *buf, size_t count,
356                      off64_t offset)
357 {
358         ERRSTACK(1);
359         struct page *page;
360         size_t copy_amt, pg_off, pg_idx;
361         volatile size_t so_far = 0;             /* volatile for waserror */
362         const uint8_t *buf_end = buf + count;
363         int error;
364
365         qlock(&f->qlock);
366         if (waserror()) {
367                 qunlock(&f->qlock);
368                 if (so_far) {
369                         poperror();
370                         return so_far;
371                 }
372                 nexterror();
373         };
374         if (offset + count > f->dir.length) {
375                 if (!f->ops->can_grow_to(f, offset + count))
376                         error(EINVAL, "can't write file to %lu bytes", offset + count);
377         }
378         f->flags |= FSF_DIRTY;
379         while (buf < buf_end) {
380                 pg_off = PGOFF(offset + so_far);
381                 pg_idx = LA2PPN(offset + so_far);
382                 error = pm_load_page(f->pm, pg_idx, &page);
383                 if (error)
384                         error(-error, "write pm_load_page failed");
385                 copy_amt = MIN(PGSIZE - pg_off, buf_end - buf);
386                 memcpy_from_safe(page2kva(page) + pg_off, buf, copy_amt);
387                 buf += copy_amt;
388                 so_far += copy_amt;
389                 atomic_or(&page->pg_flags, PG_DIRTY);
390                 pm_put_page(page);
391         }
392         assert(buf == buf_end);
393         /* We set the len *after* writing for our lockless reads.  If we set len
394          * before, then read() could start as soon as we loaded the page (all
395          * zeros), but before we wrote the actual data.  They'd get zeros instead of
396          * what we added. */
397         if (offset + count > f->dir.length)
398                 WRITE_ONCE(f->dir.length, offset + count);
399         __set_acmtime(f, FSF_MTIME | FSF_CTIME);
400         qunlock(&f->qlock);
401         poperror();
402         return so_far;
403 }
404
405 static void wstat_mode(struct fs_file *f, int new_mode)
406 {
407         ERRSTACK(1);
408         int mode;
409
410         qlock(&f->qlock);
411         if (waserror()) {
412                 qunlock(&f->qlock);
413                 nexterror();
414         }
415         if (!caller_is_username(f->dir.uid))
416                 error(EPERM, "wrong user for wstat, need %s", f->dir.uid);
417         /* Only allowing changes in permissions, not random stuff like whether it is
418          * a directory or symlink. */
419         mode = (f->dir.mode & ~S_PMASK) | (new_mode & S_PMASK);
420         WRITE_ONCE(f->dir.mode, mode);
421         __set_acmtime(f, FSF_CTIME);
422         qunlock(&f->qlock);
423         poperror();
424 }
425
426 size_t fs_file_wstat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz)
427 {
428         struct dir *m_dir;
429         size_t m_sz;
430
431         /* common trick in wstats.  we want the dir and any strings in the M.  the
432          * strings are smaller than the entire M (which is strings plus the real dir
433          * M).  the strings will be placed right after the dir (dir[1]) */
434         m_dir = kzmalloc(sizeof(struct dir) + m_buf_sz, MEM_WAIT);
435         m_sz = convM2D(m_buf, m_buf_sz, &m_dir[0], (char*)&m_dir[1]);
436         if (!m_sz) {
437                 kfree(m_dir);
438                 error(ENODATA, "couldn't convM2D");
439         }
440         /* We'll probably have similar issues for all of the strings.  At that
441          * point, we might not even bother reading the strings in. */
442         if (!emptystr(m_dir->name))
443                 error(EINVAL, "do not rename with wstat");
444         if (m_dir->mode != -1)
445                 wstat_mode(f, m_dir->mode);
446         if (m_dir->length != -1)
447                 fs_file_truncate(f, m_dir->length);
448         if ((int64_t)m_dir->atime.tv_sec != -1)
449                 set_acmtime_to(f, FSF_ATIME, &m_dir->atime);
450         if ((int64_t)m_dir->btime.tv_sec != -1)
451                 set_acmtime_to(f, FSF_BTIME, &m_dir->btime);
452         if ((int64_t)m_dir->ctime.tv_sec != -1)
453                 set_acmtime_to(f, FSF_CTIME, &m_dir->ctime);
454         if ((int64_t)m_dir->mtime.tv_sec != -1)
455                 set_acmtime_to(f, FSF_MTIME, &m_dir->mtime);
456         /* TODO: handle uid/gid/muid changes */
457         kfree(m_dir);
458         return m_sz;
459 }