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