shim_fs.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * shim_fs.h
  15. *
  16. * Definitions of types and functions for file system bookkeeping.
  17. */
  18. #ifndef _SHIM_FS_H_
  19. #define _SHIM_FS_H_
  20. #include <stdbool.h>
  21. #include <list.h>
  22. #include <pal.h>
  23. #include <shim_defs.h>
  24. #include <shim_handle.h>
  25. #include <shim_types.h>
  26. #include <shim_utils.h>
  27. struct shim_handle;
  28. #define FS_POLL_RD 0x01
  29. #define FS_POLL_WR 0x02
  30. #define FS_POLL_ER 0x04
  31. #define FS_POLL_SZ 0x08
  32. struct shim_fs_ops {
  33. /* mount: mount an uri to the certain location */
  34. int (*mount)(const char* uri, void** mount_data);
  35. int (*unmount)(void* mount_data);
  36. /* close: clean up the file state inside the handle */
  37. int (*close)(struct shim_handle* hdl);
  38. /* read: the content from the file opened as handle */
  39. ssize_t (*read)(struct shim_handle* hdl, void* buf, size_t count);
  40. /* write: the content from the file opened as handle */
  41. ssize_t (*write)(struct shim_handle* hdl, const void* buf, size_t count);
  42. /* mmap: mmap handle to address */
  43. int (*mmap)(struct shim_handle* hdl, void** addr, size_t size, int prot, int flags,
  44. off_t offset);
  45. /* flush: flush out user buffer */
  46. int (*flush)(struct shim_handle* hdl);
  47. /* seek: the content from the file opened as handle */
  48. off_t (*seek)(struct shim_handle* hdl, off_t offset, int wence);
  49. /* move, copy: rename or duplicate the file */
  50. int (*move)(const char* trim_old_name, const char* trim_new_name);
  51. int (*copy)(const char* trim_old_name, const char* trim_new_name);
  52. /* Returns 0 on success, -errno on error */
  53. int (*truncate)(struct shim_handle* hdl, off_t len);
  54. /* hstat: get status of the file */
  55. int (*hstat)(struct shim_handle* hdl, struct stat* buf);
  56. /* setflags: set flags of the file */
  57. int (*setflags)(struct shim_handle* hdl, int flags);
  58. /* hput: delete the handle and close the PAL handle. */
  59. void (*hput)(struct shim_handle* hdl);
  60. /* lock and unlock the file */
  61. int (*lock)(const char* trim_name);
  62. int (*unlock)(const char* trim_name);
  63. /* lock and unlock the file system */
  64. int (*lockfs)(void);
  65. int (*unlockfs)(void);
  66. /* checkout/reowned/checkin a single handle for migration */
  67. int (*checkout)(struct shim_handle* hdl);
  68. int (*checkin)(struct shim_handle* hdl);
  69. /* poll a single handle */
  70. /* POLL_RD|POLL_WR: return POLL_RD|POLL_WR for readable|writable,
  71. POLL_ER for failure, -EAGAIN for unknown. */
  72. /* POLL_SZ: return total size */
  73. off_t (*poll)(struct shim_handle* hdl, int poll_type);
  74. /* checkpoint/migrate the file system */
  75. ssize_t (*checkpoint)(void** checkpoint, void* mount_data);
  76. int (*migrate)(void* checkpoint, void** mount_data);
  77. };
  78. #define DENTRY_VALID 0x0001 /* this dentry is verified to be valid */
  79. #define DENTRY_NEGATIVE 0x0002 /* recently deleted or inaccessible */
  80. #define DENTRY_RECENTLY 0x0004 /* recently used */
  81. #define DENTRY_PERSIST 0x0008 /* added as a persistent dentry */
  82. #define DENTRY_HASHED 0x0010 /* added in the dcache */
  83. #define DENTRY_MOUNTPOINT 0x0040 /* this dentry is a mount point */
  84. #define DENTRY_ISLINK 0x0080 /* this dentry is a link */
  85. #define DENTRY_ISDIRECTORY 0x0100 /* this dentry is a directory */
  86. #define DENTRY_LOCKED 0x0200 /* locked by mountpoints at children */
  87. /* These flags are not used */
  88. //#define DENTRY_REACHABLE 0x0400 /* permission checked to be reachable */
  89. //#define DENTRY_UNREACHABLE 0x0800 /* permission checked to be unreachable */
  90. #define DENTRY_LISTED 0x1000 /* children in directory listed */
  91. #define DENTRY_INO_UPDATED 0x2000 /* ino updated */
  92. #define DENTRY_ANCESTOR 0x4000 /* Auto-generated dentry to connect a mount point in the \
  93. * manifest to the root, when one or more intermediate \
  94. * directories do not exist on the underlying FS. The semantics \
  95. * of subsequent changes to such directories (or attempts to \
  96. * really create them) are not currently well-defined. */
  97. // Catch memory corruption issues by checking for invalid state values
  98. #define DENTRY_INVALID_FLAGS (~0x7FFF)
  99. #define DCACHE_HASH_SIZE 1024
  100. #define DCACHE_HASH(hash) ((hash) & (DCACHE_HASH_SIZE - 1))
  101. DEFINE_LIST(shim_dentry);
  102. DEFINE_LISTP(shim_dentry);
  103. struct shim_dentry {
  104. int state; /* flags for managing state */
  105. struct shim_mount* fs; /* this dentry's mounted fs */
  106. struct shim_qstr rel_path; /* the path is relative to its mount point */
  107. struct shim_qstr name; /* caching the file's name. */
  108. /* DEP 6/16/17: For now, let's try not hashing; I suspect it is overkill for most purposes.
  109. * I'll leave the field here for now, but propose we move to a per-directory table to accelerate
  110. * lookups, rather than a global table, since this just supports one process.
  111. */
  112. LIST_TYPE(shim_dentry) hlist; /* to resolve collisions in the hash table */
  113. LIST_TYPE(shim_dentry) list; /* put dentry to different list according to its availability, \
  114. * persistent or freeable */
  115. struct shim_dentry* parent;
  116. int nchildren;
  117. LISTP_TYPE(shim_dentry) children; /* These children and siblings link */
  118. LIST_TYPE(shim_dentry) siblings;
  119. struct shim_mount* mounted;
  120. void* data;
  121. unsigned long ino;
  122. mode_t type;
  123. mode_t mode;
  124. struct shim_lock lock;
  125. REFTYPE ref_count;
  126. };
  127. struct shim_d_ops {
  128. /* open: provide a filename relative to the mount point and flags,
  129. modify the shim handle, file_data is "inode" equivalent */
  130. int (*open)(struct shim_handle* hdl, struct shim_dentry* dent, int flags);
  131. /* look up dentry and allocate internal data.
  132. *
  133. * On a successful lookup (non-error, can be negative),
  134. * this function should call get_new_dentry(), populating additional fields,
  135. * and storing the new dentry in dent.
  136. */
  137. int (*lookup)(struct shim_dentry* dent);
  138. /* this is to check file type and access, returning the stat.st_mode */
  139. int (*mode)(struct shim_dentry* dent, mode_t* mode);
  140. /* detach internal data from dentry */
  141. int (*dput)(struct shim_dentry* dent);
  142. /* create a dentry inside a directory */
  143. int (*creat)(struct shim_handle* hdl, struct shim_dentry* dir, struct shim_dentry* dent,
  144. int flags, mode_t mode);
  145. /* unlink a dentry inside a directory */
  146. int (*unlink)(struct shim_dentry* dir, struct shim_dentry* dent);
  147. /* create a directory inside a directory */
  148. int (*mkdir)(struct shim_dentry* dir, struct shim_dentry* dent, mode_t mode);
  149. /* stat: get status of the file */
  150. int (*stat)(struct shim_dentry* dent, struct stat* buf);
  151. /* extracts the symlink name and saves in link */
  152. int (*follow_link)(struct shim_dentry* dent, struct shim_qstr* link);
  153. /* set up symlink name to a dentry */
  154. int (*set_link)(struct shim_dentry* dent, const char* link);
  155. /* change the mode or owner of a dentry */
  156. int (*chmod)(struct shim_dentry* dent, mode_t mode);
  157. int (*chown)(struct shim_dentry* dent, int uid, int gid);
  158. /* change the name of a dentry */
  159. int (*rename)(struct shim_dentry* old, struct shim_dentry* new);
  160. /* readdir: given the path relative to the mount point, read the childs
  161. into the the buffer. This call always returns everything under
  162. the directory in one big buffer; you do not need to try again
  163. or keep a cursor in the directory. You do need to free the
  164. returned buffer. */
  165. int (*readdir)(struct shim_dentry* dent, struct shim_dirent** dirent);
  166. };
  167. #define MAX_PATH 4096
  168. #define MAX_FILENAME 255
  169. DEFINE_LIST(shim_mount);
  170. struct shim_mount {
  171. char type[8]; // Null-terminated.
  172. struct shim_dentry* mount_point;
  173. struct shim_qstr path;
  174. struct shim_qstr uri;
  175. struct shim_fs_ops* fs_ops;
  176. struct shim_d_ops* d_ops;
  177. struct shim_dentry* root;
  178. void* data;
  179. void* cpdata;
  180. size_t cpsize;
  181. REFTYPE ref_count;
  182. LIST_TYPE(shim_mount) hlist;
  183. LIST_TYPE(shim_mount) list;
  184. };
  185. extern struct shim_dentry* dentry_root;
  186. #define LOOKUP_FOLLOW 001
  187. #define LOOKUP_DIRECTORY 002
  188. #define LOOKUP_CONTINUE 004 // No longer needed
  189. #define LOOKUP_PARENT 010 // Not sure we need this
  190. #define F_OK 0
  191. // XXX: Duplicate definition; should probably weed out includes of host system
  192. // include of unistd.h in future work
  193. //#define R_OK 001
  194. //#define W_OK 002
  195. //#define X_OK 004
  196. #define MAY_EXEC 001
  197. #define MAY_WRITE 002
  198. #define MAY_READ 004
  199. #if 0
  200. #define MAY_APPEND 010
  201. #endif
  202. #define NO_MODE ((mode_t)-1)
  203. #define ACC_MODE(x) \
  204. ((((x) == O_RDONLY || (x) == O_RDWR) ? MAY_READ : 0) | \
  205. (((x) == O_WRONLY || (x) == O_RDWR) ? MAY_WRITE : 0))
  206. #define LOOKUP_OPEN 0100 // Appears to be ignored
  207. #define LOOKUP_CREATE 0200
  208. #define LOOKUP_ACCESS 0400 // Appears to be ignored
  209. #define LOOKUP_SYNC (LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_ACCESS)
  210. enum lookup_type {
  211. LAST_NORM,
  212. LAST_ROOT,
  213. LAST_DOT,
  214. LAST_DOTDOT,
  215. LAST_BIND
  216. };
  217. struct lookup {
  218. struct shim_dentry* dentry;
  219. struct shim_mount* mount;
  220. const char* last;
  221. int depth;
  222. int flags;
  223. enum lookup_type last_type;
  224. };
  225. /* initialization for fs and mounts */
  226. int init_fs(void);
  227. int init_mount_root(void);
  228. int init_mount(void);
  229. /* path utilities */
  230. const char* get_file_name(const char* path, size_t len);
  231. /* file system operations */
  232. int mount_fs(const char* mount_type, const char* mount_uri, const char* mount_point,
  233. struct shim_dentry* parent, struct shim_dentry** dentp, bool make_ancestor);
  234. int unmount_fs(const char* mount_point);
  235. int search_builtin_fs(const char* type, struct shim_mount** fs);
  236. void get_mount(struct shim_mount* mount);
  237. void put_mount(struct shim_mount* mount);
  238. struct shim_mount* find_mount_from_uri(const char* uri);
  239. #include <shim_utils.h>
  240. static inline void set_handle_fs(struct shim_handle* hdl, struct shim_mount* fs) {
  241. get_mount(fs);
  242. hdl->fs = fs;
  243. memcpy(hdl->fs_type, fs->type, sizeof(hdl->fs_type));
  244. }
  245. int walk_mounts(int (*walk)(struct shim_mount* mount, void* arg), void* arg);
  246. /* functions for dcache supports */
  247. int init_dcache(void);
  248. extern struct shim_lock dcache_lock;
  249. /* Checks permission (specified by mask) of a dentry. If force is not set, permission is considered
  250. * granted on invalid dentries.
  251. * Assumes that caller has acquired dcache_lock. */
  252. int permission(struct shim_dentry* dent, mode_t mask);
  253. /* This function looks up a single dentry based on its parent dentry pointer and the name. `namelen`
  254. * is the length of char* name. The dentry is returned in pointer *new.
  255. *
  256. * The caller should hold the dcache_lock.
  257. */
  258. int lookup_dentry(struct shim_dentry* parent, const char* name, int namelen,
  259. struct shim_dentry** new, struct shim_mount* fs);
  260. /* Looks up path under start dentry. Saves in dent.
  261. *
  262. * Assumes dcache_lock is held; main difference from path_lookupat is that dcache_lock is not
  263. * released on return.
  264. *
  265. * The refcount is dropped by one on the returned dentry.
  266. *
  267. * The make_ancestor flag creates pseudo-dentries for any parent paths that are not in cache and do
  268. * not exist on the underlying file system. This is intended for use only in setting up the
  269. * file system view specified in the manifest.
  270. *
  271. * If the file isnt' found, returns -ENOENT.
  272. *
  273. * If the LOOKUP_DIRECTORY flag is set, and the found file isn't a directory, returns -ENOTDIR.
  274. */
  275. int __path_lookupat(struct shim_dentry* start, const char* path, int flags,
  276. struct shim_dentry** dent, int link_depth, struct shim_mount* fs,
  277. bool make_ancestor);
  278. /* Just wraps __path_lookupat, but also acquires and releases the dcache_lock. */
  279. int path_lookupat(struct shim_dentry* start, const char* name, int flags, struct shim_dentry** dent,
  280. struct shim_mount* fs);
  281. /*
  282. * This function returns a dentry (in *dir) from a handle corresponding to dirfd.
  283. * If dirfd == AT_FDCWD returns current working directory.
  284. *
  285. * Returned dentry must be a directory.
  286. *
  287. * Increments dentry ref count by one.
  288. */
  289. int get_dirfd_dentry(int dirfd, struct shim_dentry** dir);
  290. /* Open path with given flags, in mode, similar to Unix open.
  291. *
  292. * The start dentry specifies where to begin the search.
  293. * `hdl` is an optional argument; if passed in, it is initialized to refer to the opened path.
  294. *
  295. * The result is stored in `dent`.
  296. */
  297. int open_namei(struct shim_handle* hdl, struct shim_dentry* start, const char* path, int flags,
  298. int mode, struct shim_dentry** dent);
  299. /* This function calls the low-level file system to do the work of opening file indicated by dent,
  300. * and initializing it in hdl. Flags are standard open flags.
  301. *
  302. * If O_TRUNC is specified, this function is responsible for calling the underlying truncate
  303. * function.
  304. */
  305. int dentry_open(struct shim_handle* hdl, struct shim_dentry* dent, int flags);
  306. /* This function enumerates a directory and caches the results in the dentry.
  307. *
  308. * Input: A dentry for a directory in the DENTRY_ISDIRECTORY and not in the DENTRY_LISTED state.
  309. * The dentry DENTRY_LISTED flag is set upon success.
  310. *
  311. * Return value: 0 on success, <0 on error
  312. */
  313. int list_directory_dentry(struct shim_dentry* dir);
  314. /* This function caches the contents of a directory (dent), already in the listed state, in a buffer
  315. * associated with a handle (hdl).
  316. *
  317. * This function should only be called once on a handle.
  318. *
  319. * Returns 0 on success, <0 on failure.
  320. */
  321. int list_directory_handle(struct shim_dentry* dent, struct shim_handle* hdl);
  322. /* Increment the reference count on dent */
  323. void get_dentry(struct shim_dentry* dent);
  324. /* Decrement the reference count on dent */
  325. void put_dentry(struct shim_dentry* dent);
  326. static_always_inline void fast_pathcpy(char* dst, const char* src, size_t size, char** ptr) {
  327. char* d = dst;
  328. const char* s = src;
  329. for (size_t i = 0; i < size; i++, s++, d++)
  330. *d = *s;
  331. *ptr = d;
  332. }
  333. static_always_inline char* dentry_get_path(struct shim_dentry* dent, bool on_stack,
  334. size_t* sizeptr) {
  335. struct shim_mount* fs = dent->fs;
  336. char* buffer;
  337. char* c;
  338. size_t bufsize = dent->rel_path.len + 1;
  339. if (fs)
  340. bufsize += fs->path.len + 1;
  341. if (on_stack) {
  342. c = buffer = __alloca(bufsize);
  343. } else {
  344. if (!(c = buffer = malloc(bufsize)))
  345. return NULL;
  346. }
  347. if (fs && !qstrempty(&fs->path))
  348. fast_pathcpy(c, qstrgetstr(&fs->path), fs->path.len, &c);
  349. if (dent->rel_path.len) {
  350. const char* path = qstrgetstr(&dent->rel_path);
  351. int len = dent->rel_path.len;
  352. if (c > buffer && *(c - 1) == '/') {
  353. if (*path == '/')
  354. path++;
  355. } else {
  356. if (*path != '/')
  357. *(c++) = '/';
  358. }
  359. fast_pathcpy(c, path, len, &c);
  360. }
  361. if (sizeptr)
  362. *sizeptr = c - buffer;
  363. *c = 0;
  364. return buffer;
  365. }
  366. static_always_inline const char* dentry_get_name(struct shim_dentry* dent) {
  367. return qstrgetstr(&dent->name);
  368. }
  369. /* Allocate and initialize a new dentry for path name, under parent. Return the dentry.
  370. *
  371. * `mount` is the mountpoint the dentry is under; this is typically the parent->fs, but is passed
  372. * explicitly for initializing the dentry of a mountpoint.
  373. *
  374. * If hashptr is passed (as an optimization), this is a hash of the name.
  375. *
  376. * If parent is non-null, the ref count is 2; else it is 1.
  377. *
  378. * This function also sets up both a name and a relative path
  379. */
  380. struct shim_dentry* get_new_dentry(struct shim_mount* mount, struct shim_dentry* parent,
  381. const char* name, int namelen, HASHTYPE* hashptr);
  382. /* This function searches for name/namelen (as the relative path).
  383. *
  384. * If requested, the expected hash of the dentry is returned in hashptr, primarily so that the
  385. * hashing can be reused to add the dentry later.
  386. *
  387. * The reference count on the found dentry is incremented by one.
  388. *
  389. * Used only by shim_namei.c
  390. */
  391. struct shim_dentry* __lookup_dcache(struct shim_dentry* start, const char* name, int namelen,
  392. HASHTYPE* hashptr);
  393. /* This function recursively deletes and frees all dentries under root
  394. *
  395. * XXX: Current code doesn't do a free..
  396. */
  397. int __del_dentry_tree(struct shim_dentry* root);
  398. /*
  399. * Returns true if `anc` is an ancestor of `dent`.
  400. */
  401. bool dentry_is_ancestor(struct shim_dentry* anc, struct shim_dentry* dent);
  402. /* XXX: Future work: current dcache never shrinks. Would be nice to be able to do something like LRU
  403. * under space pressure, although for a single app, this may be over-kill. */
  404. /* hashing utilities */
  405. #define MOUNT_HASH_BYTE 1
  406. #define MOUNT_HASH_WIDTH 8
  407. #define MOUNT_HASH_SIZE 256
  408. #define MOUNT_HASH(hash) ((hash) & (MOUNT_HASH_SIZE - 1))
  409. HASHTYPE hash_path(const char* path, size_t size);
  410. HASHTYPE rehash_name(HASHTYPE parent_hbuf, const char* name, size_t size);
  411. HASHTYPE rehash_path(HASHTYPE ancester_hbuf, const char* path, size_t size);
  412. extern struct shim_fs_ops chroot_fs_ops;
  413. extern struct shim_d_ops chroot_d_ops;
  414. extern struct shim_fs_ops str_fs_ops;
  415. extern struct shim_d_ops str_d_ops;
  416. extern struct shim_fs_ops dev_fs_ops;
  417. extern struct shim_d_ops dev_d_ops;
  418. extern struct shim_fs_ops config_fs_ops;
  419. extern struct shim_d_ops config_d_ops;
  420. extern struct shim_fs_ops proc_fs_ops;
  421. extern struct shim_d_ops proc_d_ops;
  422. extern struct shim_mount chroot_builtin_fs;
  423. extern struct shim_mount pipe_builtin_fs;
  424. extern struct shim_mount socket_builtin_fs;
  425. extern struct shim_mount epoll_builtin_fs;
  426. extern struct shim_mount eventfd_builtin_fs;
  427. /* proc file system */
  428. struct proc_nm_ops {
  429. int (*match_name)(const char* name);
  430. int (*list_name)(const char* name, struct shim_dirent** buf, int count);
  431. };
  432. struct proc_fs_ops {
  433. int (*open)(struct shim_handle* hdl, const char* name, int flags);
  434. int (*mode)(const char* name, mode_t* mode);
  435. int (*stat)(const char* name, struct stat* buf);
  436. int (*follow_link)(const char* name, struct shim_qstr* link);
  437. };
  438. struct proc_dir;
  439. struct proc_ent {
  440. const char* name; /* A proc_callback should at least have a name or nm_ops. Otherwise, it is a
  441. * NULL-end. */
  442. const struct proc_nm_ops* nm_ops;
  443. const struct proc_fs_ops* fs_ops;
  444. const struct proc_dir* dir;
  445. };
  446. struct proc_dir {
  447. int size;
  448. const struct proc_ent ent[];
  449. };
  450. /* string-type file system */
  451. int str_add_dir(const char* path, mode_t mode, struct shim_dentry** dent);
  452. int str_add_file(const char* path, mode_t mode, struct shim_dentry** dent);
  453. int str_open(struct shim_handle* hdl, struct shim_dentry* dent, int flags);
  454. int str_dput(struct shim_dentry* dent);
  455. int str_close(struct shim_handle* hdl);
  456. ssize_t str_read(struct shim_handle* hdl, void* buf, size_t count);
  457. ssize_t str_write(struct shim_handle* hdl, const void* buf, size_t count);
  458. off_t str_seek(struct shim_handle* hdl, off_t offset, int whence);
  459. int str_flush(struct shim_handle* hdl);
  460. #endif /* _SHIM_FS_H_ */