9ns: Clean up the dir->mode bits
[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 stores all the DM bits, but note that userspace can only affect
90          * the permissions (S_PMASK) bits. */
91         dir->mode = perm;
92         __set_acmtime(f, FSF_ATIME | FSF_BTIME | FSF_MTIME | FSF_CTIME);
93         dir->length = 0;
94         /* TODO: this is a mess if you use anything other than eve.  If you use a
95          * process, that memory is sitting in the proc struct, but we have weak refs
96          * on it.  What happens when that proc exits?  Disaster. */
97         assert(user == &eve);
98         dir->uid = user->name;
99         dir->gid = user->name;
100         dir->muid = user->name;
101 }
102
103 static char *copy_str(const char *s)
104 {
105         char *ret;
106         size_t sz;
107
108         if (!s)
109                 return NULL;
110         sz = strlen(s) + 1;
111         ret = kmalloc(sz, MEM_WAIT);
112         memcpy(ret, s, sz);
113         return ret;
114 }
115
116 /* Deep copies the contents of dir into the fs_file's dir. */
117 void fs_file_copy_from_dir(struct fs_file *f, struct dir *dir)
118 {
119         memcpy(&f->dir, dir, sizeof(struct dir));
120         fs_file_set_basename(f, dir->name);
121         /* TODO: sort out usernames.  Not only are these just eve, but they are not
122          * struct user or something and they ignore whatever the name was from the
123          * remote end. */
124         f->dir.uid = eve.name;
125         f->dir.gid = eve.name;
126         f->dir.muid = eve.name;
127         f->dir.ext = copy_str(dir->ext);
128 }
129
130 void cleanup_fs_file(struct fs_file *f)
131 {
132         if (f->dir.name != f->static_name)
133                 kfree(f->dir.name);
134         /* TODO: Not sure if these will be refcounted objects in the future.  Keep
135          * this in sync with other code that manages/sets uid/gid/muid. */
136         f->dir.uid = NULL;
137         f->dir.gid = NULL;
138         f->dir.muid = NULL;
139         if (f->dir.ext)
140                 kfree(f->dir.ext);
141         f->dir.ext = NULL;
142         pm_destroy(f->pm);
143         /* Might share mappings in the future.  Catch it here. */
144         assert(f->pm == &f->static_pm);
145 }
146
147 void __set_acmtime_to(struct fs_file *f, int which, struct timespec *t)
148 {
149         /* WRITE_ONCE, due to lockless peakers */
150         if (which & FSF_ATIME) {
151                 WRITE_ONCE(f->dir.atime.tv_sec, t->tv_sec);
152                 WRITE_ONCE(f->dir.atime.tv_nsec, t->tv_nsec);
153         }
154         if (which & FSF_BTIME) {
155                 WRITE_ONCE(f->dir.btime.tv_sec, t->tv_sec);
156                 WRITE_ONCE(f->dir.btime.tv_nsec, t->tv_nsec);
157         }
158         if (which & FSF_CTIME) {
159                 WRITE_ONCE(f->dir.ctime.tv_sec, t->tv_sec);
160                 WRITE_ONCE(f->dir.ctime.tv_nsec, t->tv_nsec);
161         }
162         if (which & FSF_MTIME) {
163                 WRITE_ONCE(f->dir.mtime.tv_sec, t->tv_sec);
164                 WRITE_ONCE(f->dir.mtime.tv_nsec, t->tv_nsec);
165         }
166 }
167
168 /* Caller should hold f's qlock */
169 void __set_acmtime(struct fs_file *f, int which)
170 {
171         struct timespec now = nsec2timespec(epoch_nsec());
172
173         __set_acmtime_to(f, which, &now);
174 }
175
176 /* Recall that the frontend always has the most up-to-date info.  This gets
177  * synced to the backend when we flush or fsync. */
178 void set_acmtime_to(struct fs_file *f, int which, struct timespec *t)
179 {
180         ERRSTACK(1);
181
182         qlock(&f->qlock);
183         if (waserror()) {
184                 qunlock(&f->qlock);
185                 nexterror();
186         }
187         if ((which & FSF_ATIME) && !caller_has_file_perms(f, O_READ))
188                 error(EPERM, "insufficient perms to set atime");
189         if ((which & FSF_BTIME) && !caller_is_username(f->dir.uid))
190                 error(EPERM, "insufficient perms to set btime");
191         if ((which & FSF_CTIME) && !caller_has_file_perms(f, O_WRITE))
192                 error(EPERM, "insufficient perms to set ctime");
193         if ((which & FSF_MTIME) && !caller_has_file_perms(f, O_WRITE))
194                 error(EPERM, "insufficient perms to set mtime");
195         __set_acmtime_to(f, which, t);
196         qunlock(&f->qlock);
197         poperror();
198 }
199
200 void set_acmtime_noperm(struct fs_file *f, int which)
201 {
202         struct timespec now = nsec2timespec(epoch_nsec());
203
204         /* <3 atime.  We'll go with an hour resolution, like NTFS. */
205         if (which == FSF_ATIME) {
206                 if (now.tv_sec < ACCESS_ONCE(f->dir.atime.tv_sec) + 3600)
207                         return;
208         }
209         qlock(&f->qlock);
210         __set_acmtime_to(f, which, &now);
211         qunlock(&f->qlock);
212 }
213
214 size_t fs_file_stat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz)
215 {
216         size_t ret;
217
218         qlock(&f->qlock);
219         ret = convD2M(&f->dir, m_buf, m_buf_sz);
220         qunlock(&f->qlock);
221         if (ret <= BIT16SZ)
222                 error(EINVAL, "buffer too small for stat");
223         return ret;
224 }
225
226 /* Punches a hole from begin to end.  Pages completely in the hole will be
227  * removed.  Otherwise, the edges will be zeroed.  Caller holds the qlock. */
228 static void __fs_file_punch_hole(struct fs_file *f, off64_t begin, off64_t end)
229 {
230         size_t first_pg_idx, last_pg_idx, nr_pages, zero_amt;
231         struct page *page;
232         int error;
233
234         /* Caller should check for this */
235         assert((long)begin >= 0);
236         assert((long)end >= 0);
237         end = MIN(end, f->dir.length);
238         if (end <= begin)
239                 return;
240         first_pg_idx = LA2PPN(begin);
241         last_pg_idx = LA2PPN(end);
242         nr_pages = last_pg_idx - first_pg_idx + 1;
243         if (PGOFF(begin)) {
244                 error = pm_load_page(f->pm, first_pg_idx, &page);
245                 if (error)
246                         error(-error, "punch_hole pm_load_page failed");
247                 zero_amt = MIN(PGSIZE - PGOFF(begin), end - begin);
248                 memset(page2kva(page) + PGOFF(begin), 0, zero_amt);
249                 atomic_or(&page->pg_flags, PG_DIRTY);
250                 pm_put_page(page);
251                 first_pg_idx--;
252                 nr_pages--;
253                 if (!nr_pages)
254                         return;
255         }
256         if (PGOFF(end) && (end < f->dir.length)) {
257                 error = pm_load_page(f->pm, last_pg_idx, &page);
258                 if (error)
259                         error(-error, "punch_hole pm_load_page failed");
260                 memset(page2kva(page), 0, PGOFF(end));
261                 atomic_or(&page->pg_flags, PG_DIRTY);
262                 pm_put_page(page);
263                 nr_pages--;
264                 if (!nr_pages)
265                         return;
266         }
267         /* We hold the qlock, so new pages won't get loaded (load_nowait will fail).
268          * However, this won't remove all pages yet! (see PM comments above) */
269         pm_remove_contig(f->pm, first_pg_idx, nr_pages);
270         /* Need to do an FS op to immediately tell the backing store before we read
271          * a page back in to the PM.  Otherwise, we might see old data.  Consider a
272          * truncate to 0, then back to len. */
273         f->ops->punch_hole(f, begin, end);
274 }
275
276 void fs_file_truncate(struct fs_file *f, off64_t to)
277 {
278         ERRSTACK(1);
279
280         fs_file_perm_check(f, O_WRITE);
281         qlock(&f->qlock);
282         if (waserror()) {
283                 qunlock(&f->qlock);
284                 nexterror();
285         }
286         if (to < f->dir.length) {
287                 __fs_file_punch_hole(f, to, f->dir.length);
288         } else {
289                 if (!f->ops->can_grow_to(f, to))
290                         error(EINVAL, "can't grow file to %lu bytes", to);
291         }
292         WRITE_ONCE(f->dir.length, to);
293         __set_acmtime(f, FSF_MTIME | FSF_CTIME);
294         qunlock(&f->qlock);
295         poperror();
296 }
297
298 /* This attempts to avoid the file qlock when pages are in the page cache.
299  *
300  * If we want to go simpler and use the qlock, always check len, don't use
301  * _nowait, it's not a 'lockless peak', write can set the len at the top, and
302  * all writes to dir.length can be normal. */
303 size_t fs_file_read(struct fs_file *f, uint8_t *buf, size_t count,
304                     off64_t offset)
305 {
306         ERRSTACK(1);
307         struct page *page;
308         size_t copy_amt, pg_off, pg_idx, total_remaining;
309         volatile size_t so_far = 0;             /* volatile for waserror */
310         const uint8_t *buf_end = buf + count;
311         int error;
312
313         if (waserror()) {
314                 if (so_far) {
315                         poperror();
316                         return so_far;
317                 }
318                 nexterror();
319         }
320         while (buf < buf_end) {
321                 pg_off = PGOFF(offset + so_far);
322                 pg_idx = LA2PPN(offset + so_far);
323                 error = pm_load_page_nowait(f->pm, pg_idx, &page);
324                 if (error == -EAGAIN) {
325                         qlock(&f->qlock);
326                         /* Don't attempt to load pages beyond len.  The rest of the read
327                          * code can handle it (it won't copy), but the backend FS might get
328                          * confused. */
329                         if (f->dir.length <= offset + so_far) {
330                                 qunlock(&f->qlock);
331                                 break;
332                         }
333                         error = pm_load_page(f->pm, pg_idx, &page);
334                         qunlock(&f->qlock);
335                 }
336                 if (error)
337                         error(-error, "read pm_load_page failed");
338                 copy_amt = MIN(PGSIZE - pg_off, buf_end - buf);
339                 /* Lockless peak.  Check the len so we don't read beyond EOF.  We have a
340                  * page, but we don't necessarily have access to all of it. */
341                 total_remaining = ACCESS_ONCE(f->dir.length) - (offset + so_far);
342                 if (copy_amt > total_remaining) {
343                         copy_amt = total_remaining;
344                         buf_end = buf + copy_amt;
345                 }
346                 memcpy_to_safe(buf, page2kva(page) + pg_off, copy_amt);
347                 buf += copy_amt;
348                 so_far += copy_amt;
349                 pm_put_page(page);
350         }
351         if (so_far)
352                 set_acmtime_noperm(f, FSF_ATIME);
353         poperror();
354         return so_far;
355 }
356
357 size_t fs_file_write(struct fs_file *f, const uint8_t *buf, size_t count,
358                      off64_t offset)
359 {
360         ERRSTACK(1);
361         struct page *page;
362         size_t copy_amt, pg_off, pg_idx;
363         volatile size_t so_far = 0;             /* volatile for waserror */
364         const uint8_t *buf_end = buf + count;
365         int error;
366
367         qlock(&f->qlock);
368         if (waserror()) {
369                 qunlock(&f->qlock);
370                 if (so_far) {
371                         poperror();
372                         return so_far;
373                 }
374                 nexterror();
375         };
376         if (offset + count > f->dir.length) {
377                 if (!f->ops->can_grow_to(f, offset + count))
378                         error(EINVAL, "can't write file to %lu bytes", offset + count);
379         }
380         f->flags |= FSF_DIRTY;
381         while (buf < buf_end) {
382                 pg_off = PGOFF(offset + so_far);
383                 pg_idx = LA2PPN(offset + so_far);
384                 error = pm_load_page(f->pm, pg_idx, &page);
385                 if (error)
386                         error(-error, "write pm_load_page failed");
387                 copy_amt = MIN(PGSIZE - pg_off, buf_end - buf);
388                 memcpy_from_safe(page2kva(page) + pg_off, buf, copy_amt);
389                 buf += copy_amt;
390                 so_far += copy_amt;
391                 atomic_or(&page->pg_flags, PG_DIRTY);
392                 pm_put_page(page);
393         }
394         assert(buf == buf_end);
395         /* We set the len *after* writing for our lockless reads.  If we set len
396          * before, then read() could start as soon as we loaded the page (all
397          * zeros), but before we wrote the actual data.  They'd get zeros instead of
398          * what we added. */
399         if (offset + count > f->dir.length)
400                 WRITE_ONCE(f->dir.length, offset + count);
401         __set_acmtime(f, FSF_MTIME | FSF_CTIME);
402         qunlock(&f->qlock);
403         poperror();
404         return so_far;
405 }
406
407 static void wstat_mode(struct fs_file *f, int new_mode)
408 {
409         ERRSTACK(1);
410         int mode;
411
412         qlock(&f->qlock);
413         if (waserror()) {
414                 qunlock(&f->qlock);
415                 nexterror();
416         }
417         if (!caller_is_username(f->dir.uid))
418                 error(EPERM, "wrong user for wstat, need %s", f->dir.uid);
419         /* Only allowing changes in permissions, not random stuff like whether it is
420          * a directory or symlink. */
421         static_assert(!(DMMODE_BITS & S_PMASK));
422         mode = (f->dir.mode & ~S_PMASK) | (new_mode & S_PMASK);
423         WRITE_ONCE(f->dir.mode, mode);
424         __set_acmtime(f, FSF_CTIME);
425         qunlock(&f->qlock);
426         poperror();
427 }
428
429 size_t fs_file_wstat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz)
430 {
431         struct dir *m_dir;
432         size_t m_sz;
433
434         /* common trick in wstats.  we want the dir and any strings in the M.  the
435          * strings are smaller than the entire M (which is strings plus the real dir
436          * M).  the strings will be placed right after the dir (dir[1]) */
437         m_dir = kzmalloc(sizeof(struct dir) + m_buf_sz, MEM_WAIT);
438         m_sz = convM2D(m_buf, m_buf_sz, &m_dir[0], (char*)&m_dir[1]);
439         if (!m_sz) {
440                 kfree(m_dir);
441                 error(ENODATA, "couldn't convM2D");
442         }
443         /* We'll probably have similar issues for all of the strings.  At that
444          * point, we might not even bother reading the strings in. */
445         if (!emptystr(m_dir->name))
446                 error(EINVAL, "do not rename with wstat");
447         if (m_dir->mode != -1)
448                 wstat_mode(f, m_dir->mode);
449         if (m_dir->length != -1)
450                 fs_file_truncate(f, m_dir->length);
451         if ((int64_t)m_dir->atime.tv_sec != -1)
452                 set_acmtime_to(f, FSF_ATIME, &m_dir->atime);
453         if ((int64_t)m_dir->btime.tv_sec != -1)
454                 set_acmtime_to(f, FSF_BTIME, &m_dir->btime);
455         if ((int64_t)m_dir->ctime.tv_sec != -1)
456                 set_acmtime_to(f, FSF_CTIME, &m_dir->ctime);
457         if ((int64_t)m_dir->mtime.tv_sec != -1)
458                 set_acmtime_to(f, FSF_MTIME, &m_dir->mtime);
459         /* TODO: handle uid/gid/muid changes */
460         kfree(m_dir);
461         return m_sz;
462 }