1 /* Copyright (c) 2018 Google Inc
2 * Barret Rhoden <brho@cs.berkeley.edu>
3 * See LICENSE for details.
5 * fs_file: structs and helpers for files for 9ns devices
13 /* fs_file has all the info of the 9ns dir and the dirtab (which is a subset of
14 * struct dir), plus whatever is needed for generic mmappable filesystems.
15 * Specifically, it has a page_map and a few synchronization fields. It doesn't
16 * need to support mmap either. Longer range, fs_file can replace dirtab for
17 * static device filesystems.
19 * Most fs_files will end up being tree_files (see below). Some devices might
20 * use fs_files that are hooked in to their own tree structures.
22 * fs_info is for devices to use. For instance, #mnt will probably have an
23 * actual chan for every walked fs_file. It will use that chan/FID for all of
24 * its operations on the backend: walking to discover child files, stat()ing to
25 * get fs_file metadata, reading and writing pages for the page cache, etc.
28 * Synchronization rules
30 * Note this qlock is also used by tree_file code. See below for details.
32 * Hold the qlock when changing the metadata of a file. This includes changing
33 * parts of dir (length, name, permissions/mode, atimes), etc. Tree files will
34 * hold this qlock when changing a parent's children. See the notes around
35 * fs_file_punch_hole for details about read, write, trunc, and the length.
37 * Readers who just 'peak' at atomically-writable fields do not need to grab the
38 * qlock. For example, you can glance at dir->perms. In arbitrary cases, you
39 * can't look at name, since we can't change it atomically (it can smear or run
40 * into other issues). 'name' is somewhat special: if you find the tree_file
41 * via a RCU protected wc hash lookup, you can access name.
43 * There's actually not a lot in dir that is atomically writable.
44 * atime/mtime/ctime won't be when we use timespecs. We might be able to craft
45 * something for lockless reads of dir state with seq counters. That would save
46 * a qlock for each fs_file on a readdir. It's a little tricky; we probably
47 * need to kfree_rcu the dir->name (never leak in a convD2M, even if we retry),
48 * and we need to be careful about multi-field changes where the changer might
49 * block. i.e. don't hold a seq lock when making a backend op, which could
50 * block. Not too concerned with this for now, esp since it's not clear how
53 * Note that even if we can atomically write to the dir, we should still grab
54 * the qlock. Often we're syncing with other writers anyways, and there may be
55 * readers who want to make sure parts of the dir doesn't change. When we do
56 * write a field that can be locklessly read, use WRITE_ONCE.
58 * The PM code is pretty rough. For now, we're using the old VFS PM code, but
59 * it needs a few changes:
60 * - Heavily integrated with struct page. Maybe some sort of 'struct page' on
61 * demand, that is built for an IO mapping. There might be some huge-page
63 * - The pm_ops callbacks and whatnot could use some help, even just the
64 * arguments and indirections. Maybe integrate them more into the funcs, e.g.
65 * fs_file_*(). They probably should be fs_file_ops. For now, the pm ops
66 * assume the qlock is held.
71 /* TODO: Once we get rid of the VFS and rework the PM, we can put the PM ops in
74 struct page_map_operations; /* readpage and writepage */
75 void (*punch_hole)(struct fs_file *f, off64_t begin, off64_t end);
76 bool (*can_grow_to)(struct fs_file *f, size_t len);
79 #define FSF_DIRTY (1 << 1)
85 struct fs_file_ops *ops;
89 /* optional inline storage */
90 char static_name[KNAMELEN]; /* for dir->name */
91 struct page_map static_pm; /* for pm */
92 /* we need to be aligned to 64 bytes for the linker tables. */
93 } __attribute__ ((aligned(64)));
95 static inline bool caller_has_file_perms(struct fs_file *f, int omode)
97 return caller_has_dir_perms(&f->dir, omode);
100 static inline void fs_file_perm_check(struct fs_file *f, int omode)
102 dir_perm_check(&f->dir, omode);
105 static inline size_t fs_file_get_length(struct fs_file *f)
107 return ACCESS_ONCE(f->dir.length);
110 void fs_file_init(struct fs_file *f, const char *name, struct fs_file_ops *ops);
111 void fs_file_set_basename(struct fs_file *f, const char *name);
112 void fs_file_change_basename(struct fs_file *f, const char *name);
113 void fs_file_init_dir(struct fs_file *f, int dir_type, int dir_dev,
114 struct username *user, int perm);
115 void fs_file_copy_from_dir(struct fs_file *f, struct dir *dir);
116 void cleanup_fs_file(struct fs_file *f);
118 #define FSF_ATIME (1 << 0)
119 #define FSF_BTIME (1 << 1)
120 #define FSF_CTIME (1 << 2)
121 #define FSF_MTIME (1 << 3)
123 void __set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
124 void __set_acmtime(struct fs_file *f, int which);
125 void set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
126 void set_acmtime_noperm(struct fs_file *f, int which);
128 size_t fs_file_stat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);
129 void fs_file_truncate(struct fs_file *f, off64_t to);
130 size_t fs_file_read(struct fs_file *f, uint8_t *buf, size_t count,
132 size_t fs_file_write(struct fs_file *f, const uint8_t *buf, size_t count,
134 size_t fs_file_wstat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);