shim_fs.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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 <shim_types.h>
  22. #include <shim_defs.h>
  23. #include <shim_handle.h>
  24. #include <shim_utils.h>
  25. #include <pal.h>
  26. #include <list.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,
  44. int prot, int flags, 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 filesystem */
  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 /* negative, recently deleted */
  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
  93. * point in the manifest to the root, when
  94. * one or more intermediate directories do
  95. * not exist on the underlying FS. The
  96. * semantics of subsequent changes to such
  97. * directories (or attempts to really
  98. * create them) are not currently
  99. * well-defined. */
  100. // Catch memory corruption issues by checking for invalid state values
  101. #define DENTRY_INVALID_FLAGS (~0x7FFF)
  102. #define DCACHE_HASH_SIZE 1024
  103. #define DCACHE_HASH(hash) ((hash) & (DCACHE_HASH_SIZE - 1))
  104. DEFINE_LIST(shim_dentry);
  105. DEFINE_LISTP(shim_dentry);
  106. struct shim_dentry {
  107. int state; /* flags for managing state */
  108. struct shim_mount * fs; /* this dentry's mounted fs */
  109. struct shim_qstr rel_path; /* the path is relative to
  110. its mount point */
  111. struct shim_qstr name; /* caching the file's name. */
  112. /* DEP 6/16/17: For now, let's try not hashing; I suspect it is
  113. * overkill for most purposes. I'll leave the field here for now,
  114. * but propose we move to a per-directory table to accelerate lookups,
  115. * rather than a global table, since this just supports one process.
  116. */
  117. LIST_TYPE(shim_dentry) hlist; /* to resolve collisions in
  118. the hash table */
  119. LIST_TYPE(shim_dentry) list; /* put dentry to different list
  120. according to its availability,
  121. persistent or freeable */
  122. struct shim_dentry * parent;
  123. int nchildren;
  124. LISTP_TYPE(shim_dentry) children; /* These children and siblings link */
  125. LIST_TYPE(shim_dentry) siblings;
  126. struct shim_mount * mounted;
  127. void * data;
  128. unsigned long ino;
  129. mode_t type;
  130. mode_t mode;
  131. struct shim_lock lock;
  132. REFTYPE ref_count;
  133. };
  134. struct shim_d_ops {
  135. /* open: provide a filename relative to the mount point and flags,
  136. modify the shim handle, file_data is "inode" equivalent */
  137. int (*open) (struct shim_handle * hdl, struct shim_dentry * dent,
  138. int flags);
  139. /* look up dentry and allocate internal data.
  140. *
  141. * On a successful lookup (non-error, can be negative),
  142. * this function should call get_new_dentry(), populating additional fields,
  143. * and storing the new dentry in dent.
  144. */
  145. int (*lookup) (struct shim_dentry * dent);
  146. /* this is to check file type and access, returning the stat.st_mode */
  147. int (*mode) (struct shim_dentry * dent, mode_t * mode);
  148. /* detach internal data from dentry */
  149. int (*dput) (struct shim_dentry * dent);
  150. /* create a dentry inside a directory */
  151. int (*creat) (struct shim_handle * hdl, struct shim_dentry * dir,
  152. struct shim_dentry * dent, int flags, mode_t mode);
  153. /* unlink a dentry inside a directory */
  154. int (*unlink) (struct shim_dentry * dir, struct shim_dentry * dent);
  155. /* create a directory inside a directory */
  156. int (*mkdir) (struct shim_dentry * dir, struct shim_dentry * dent,
  157. mode_t mode);
  158. /* stat: get status of the file */
  159. int (*stat) (struct shim_dentry * dent, struct stat * buf);
  160. /* extracts the symlink name and saves in link */
  161. int (*follow_link) (struct shim_dentry * dent, struct shim_qstr * link);
  162. /* set up symlink name to a dentry */
  163. int (*set_link) (struct shim_dentry * dent, const char * link);
  164. /* change the mode or owner of a dentry */
  165. int (*chmod) (struct shim_dentry * dent, mode_t mode);
  166. int (*chown) (struct shim_dentry * dent, int uid, int gid);
  167. /* change the name of a dentry */
  168. int (*rename) (struct shim_dentry * old, struct shim_dentry * new);
  169. /* readdir: given the path relative to the mount point, read the childs
  170. into the the buffer. This call always returns everything under
  171. the directory in one big buffer; you do not need to try again
  172. or keep a cursor in the directory. You do need to free the
  173. returned buffer. */
  174. int (*readdir) (struct shim_dentry * dent, struct shim_dirent ** dirent);
  175. };
  176. #define MAX_PATH 4096
  177. #define MAX_FILENAME 255
  178. DEFINE_LIST(shim_mount);
  179. struct shim_mount {
  180. char type[8]; // Null-terminated.
  181. struct shim_dentry * mount_point;
  182. struct shim_qstr path;
  183. struct shim_qstr uri;
  184. struct shim_fs_ops * fs_ops;
  185. struct shim_d_ops * d_ops;
  186. struct shim_dentry * root;
  187. void * data;
  188. void * cpdata;
  189. size_t cpsize;
  190. REFTYPE ref_count;
  191. LIST_TYPE(shim_mount) hlist;
  192. LIST_TYPE(shim_mount) list;
  193. };
  194. extern struct shim_dentry * dentry_root;
  195. #define LOOKUP_FOLLOW 001
  196. #define LOOKUP_DIRECTORY 002
  197. #define LOOKUP_CONTINUE 004 // No longer needed
  198. #define LOOKUP_PARENT 010 // Not sure we need this
  199. #define F_OK 0
  200. // XXX: Duplicate definition; should probably weed out includes of host system
  201. //include of unistd.h in future work
  202. //#define R_OK 001
  203. //#define W_OK 002
  204. //#define X_OK 004
  205. #define MAY_EXEC 001
  206. #define MAY_WRITE 002
  207. #define MAY_READ 004
  208. #if 0
  209. #define MAY_APPEND 010
  210. #endif
  211. #define NO_MODE ((mode_t) -1)
  212. #define ACC_MODE(x) ((((x) == O_RDONLY || (x) == O_RDWR) ? MAY_READ : 0) | \
  213. (((x) == O_WRONLY || (x) == O_RDWR) ? MAY_WRITE : 0))
  214. #define LOOKUP_OPEN 0100 // Appears to be ignored
  215. #define LOOKUP_CREATE 0200
  216. #define LOOKUP_ACCESS 0400 // Appears to be ignored
  217. #define LOOKUP_SYNC (LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_ACCESS)
  218. enum lookup_type {
  219. LAST_NORM,
  220. LAST_ROOT,
  221. LAST_DOT,
  222. LAST_DOTDOT,
  223. LAST_BIND
  224. };
  225. struct lookup {
  226. struct shim_dentry * dentry;
  227. struct shim_mount * mount;
  228. const char * last;
  229. int depth;
  230. int flags;
  231. enum lookup_type last_type;
  232. };
  233. /* initialization for fs and mounts */
  234. int init_fs (void);
  235. int init_mount_root (void);
  236. int init_mount (void);
  237. /* path utilities */
  238. const char * get_file_name (const char * path, size_t len);
  239. /* file system operations */
  240. int mount_fs (const char * mount_type, const char * mount_uri,
  241. const char * mount_point, struct shim_dentry *parent,
  242. struct shim_dentry **dentp, bool make_ancestor);
  243. int unmount_fs (const char * mount_point);
  244. int search_builtin_fs (const char * type, struct shim_mount ** fs);
  245. void get_mount (struct shim_mount * mount);
  246. void put_mount (struct shim_mount * mount);
  247. struct shim_mount * find_mount_from_uri (const char * uri);
  248. #include <shim_utils.h>
  249. static inline void set_handle_fs (struct shim_handle * hdl,
  250. struct shim_mount * fs)
  251. {
  252. get_mount(fs);
  253. hdl->fs = fs;
  254. memcpy(hdl->fs_type, fs->type, sizeof(hdl->fs_type));
  255. }
  256. int walk_mounts (int (*walk) (struct shim_mount * mount, void * arg),
  257. void * arg);
  258. /* functions for dcache supports */
  259. int init_dcache (void);
  260. extern struct shim_lock dcache_lock;
  261. /* check permission (specified by mask) of a dentry. If force is not set,
  262. * permission is considered granted on invalid dentries */
  263. /* Assume caller has acquired dcache_lock */
  264. int permission (struct shim_dentry * dent, mode_t mask);
  265. /* This function looks up a single dentry based on its parent dentry pointer
  266. * and the name. Namelen is the length of char * name.
  267. * The dentry is returned in pointer *new.
  268. *
  269. * The caller should hold the dcache_lock.
  270. */
  271. int lookup_dentry (struct shim_dentry * parent, const char * name, int namelen,
  272. struct shim_dentry ** new, struct shim_mount * fs);
  273. /* Looks up path under start dentry. Saves in dent.
  274. *
  275. * Assumes dcache_lock is held; main difference from path_lookupat is that
  276. * dcache_lock is not released on return.
  277. *
  278. * The refcount is dropped by one on the returned dentry.
  279. *
  280. * The make_ancestor flag creates pseudo-dentries for any parent paths that
  281. * are not in cache and do not exist on the underlying file system. This is
  282. * intended for use only in setting up the file system view specified in the manifest.
  283. *
  284. * If the file isnt' found, returns -ENOENT.
  285. *
  286. * If the LOOKUP_DIRECTORY flag is set, and the found file isn't a directory,
  287. * returns -ENOTDIR.
  288. */
  289. int __path_lookupat (struct shim_dentry * start, const char * path, int flags,
  290. struct shim_dentry ** dent, int link_depth,
  291. struct shim_mount *fs, bool make_ancestor);
  292. /* Just wraps __path_lookupat, but also acquires and releases the dcache_lock.
  293. */
  294. int path_lookupat (struct shim_dentry * start, const char * name, int flags,
  295. struct shim_dentry ** dent, struct shim_mount *fs);
  296. /*
  297. * This function returns a dentry (in *dir) from a handle corresponding to dirfd.
  298. * If dirfd == AT_FDCWD returns current working directory.
  299. *
  300. * Returned dentry must be a directory.
  301. *
  302. * Increments dentry ref count by one.
  303. */
  304. int get_dirfd_dentry(int dirfd, struct shim_dentry** dir);
  305. /* Open path with given flags, in mode, similar to Unix open.
  306. *
  307. * The start dentry specifies where to begin the search.
  308. * hdl is an optional argument; if passed in, it is initialized to
  309. * refer to the opened path.
  310. *
  311. * The result is stored in dent.
  312. */
  313. int open_namei (struct shim_handle * hdl, struct shim_dentry * start,
  314. const char * path, int flags, int mode,
  315. struct shim_dentry ** dent);
  316. /* This function calls the low-level file system to do the work
  317. * of opening file indicated by dent, and initializing it in hdl.
  318. * Flags are standard open flags.
  319. *
  320. * If O_TRUNC is specified, this function is responsible for calling
  321. * the underlying truncate function.
  322. */
  323. int dentry_open (struct shim_handle * hdl, struct shim_dentry * dent,
  324. int flags);
  325. /* This function enumerates a directory and caches the results in the dentry.
  326. *
  327. * Input: A dentry for a directory in the DENTRY_ISDIRECTORY and not in the
  328. * DENTRY_LISTED state. The dentry DENTRY_LISTED flag is set upon success.
  329. *
  330. * Return value: 0 on success, <0 on error
  331. */
  332. int list_directory_dentry (struct shim_dentry *dir);
  333. /* This function caches the contents of a directory (dent), already
  334. * in the listed state, in a buffer associated with a handle (hdl).
  335. *
  336. * This function should only be called once on a handle.
  337. *
  338. * Returns 0 on success, <0 on failure.
  339. */
  340. int list_directory_handle (struct shim_dentry *dent, struct shim_handle *hdl );
  341. /* Increment the reference count on dent */
  342. void get_dentry (struct shim_dentry * dent);
  343. /* Decrement the reference count on dent */
  344. void put_dentry (struct shim_dentry * dent);
  345. static_always_inline
  346. void fast_pathcpy (char * dst, const char * src, size_t size, char ** ptr)
  347. {
  348. char * d = dst;
  349. const char * s = src;
  350. for (size_t i = 0 ; i < size ; i++, s++, d++)
  351. *d = *s;
  352. *ptr = d;
  353. }
  354. static_always_inline
  355. char * dentry_get_path (struct shim_dentry * dent, bool on_stack,
  356. size_t * sizeptr)
  357. {
  358. struct shim_mount * fs = dent->fs;
  359. char * buffer, * c;
  360. size_t bufsize = dent->rel_path.len + 1;
  361. if (fs)
  362. bufsize += fs->path.len + 1;
  363. if (on_stack) {
  364. c = buffer = __alloca(bufsize);
  365. } else {
  366. if (!(c = buffer = malloc(bufsize)))
  367. return NULL;
  368. }
  369. if (fs && !qstrempty(&fs->path))
  370. fast_pathcpy(c, qstrgetstr(&fs->path), fs->path.len, &c);
  371. if (dent->rel_path.len) {
  372. const char * path = qstrgetstr(&dent->rel_path);
  373. int len = dent->rel_path.len;
  374. if (c > buffer && *(c - 1) == '/') {
  375. if (*path == '/')
  376. path++;
  377. } else {
  378. if (*path != '/')
  379. *(c++) = '/';
  380. }
  381. fast_pathcpy(c, path, len, &c);
  382. }
  383. if (sizeptr)
  384. *sizeptr = c - buffer;
  385. *c = 0;
  386. return buffer;
  387. }
  388. static_always_inline
  389. const char * dentry_get_name (struct shim_dentry * dent)
  390. {
  391. return qstrgetstr(&dent->name);
  392. }
  393. /* Allocate and initialize a new dentry for path name, under
  394. * parent. Return the dentry.
  395. *
  396. * mount is the mountpoint the dentry is under; this is typically
  397. * the parent->fs, but is passed explicitly for initializing
  398. * the dentry of a mountpoint.
  399. *
  400. * If hashptr is passed (as an optimization), this is a hash
  401. * of the name.
  402. *
  403. * If parent is non-null, the ref count is 2; else it is 1.
  404. *
  405. * This function also sets up both a name and a relative path
  406. */
  407. struct shim_dentry * get_new_dentry (struct shim_mount *mount,
  408. struct shim_dentry * parent,
  409. const char * name, int namelen,
  410. HASHTYPE * hashptr);
  411. /* This function searches for name/namelen (as the relative path).
  412. *
  413. * If requested, the expected hash of the dentry is returned in hashptr,
  414. * primarily so that the hashing can be reused to add the dentry later.
  415. *
  416. * The reference count on the found dentry is incremented by one.
  417. *
  418. * Used only by shim_namei.c
  419. */
  420. struct shim_dentry *
  421. __lookup_dcache (struct shim_dentry * start, const char * name, int namelen,
  422. HASHTYPE * hashptr);
  423. /* This function recursively deletes and frees all dentries under root
  424. *
  425. * XXX: Current code doesn't do a free..
  426. */
  427. int __del_dentry_tree(struct shim_dentry * root);
  428. /*
  429. * Returns true if `anc` is an ancestor of `dent`.
  430. */
  431. bool dentry_is_ancestor(struct shim_dentry* anc, struct shim_dentry* dent);
  432. /* XXX: Future work: current dcache never shrinks. Would be nice
  433. * to be able to do something like LRU under space pressure, although
  434. * for a single app, this may be over-kill. */
  435. /* hashing utilities */
  436. #define MOUNT_HASH_BYTE 1
  437. #define MOUNT_HASH_WIDTH 8
  438. #define MOUNT_HASH_SIZE 256
  439. #define MOUNT_HASH(hash) ((hash) & (MOUNT_HASH_SIZE - 1))
  440. HASHTYPE hash_path(const char* path, size_t size);
  441. HASHTYPE rehash_name(HASHTYPE parent_hbuf, const char* name, size_t size);
  442. HASHTYPE rehash_path(HASHTYPE ancester_hbuf, const char* path, size_t size);
  443. extern struct shim_fs_ops chroot_fs_ops;
  444. extern struct shim_d_ops chroot_d_ops;
  445. extern struct shim_fs_ops str_fs_ops;
  446. extern struct shim_d_ops str_d_ops;
  447. extern struct shim_fs_ops dev_fs_ops;
  448. extern struct shim_d_ops dev_d_ops;
  449. extern struct shim_fs_ops config_fs_ops;
  450. extern struct shim_d_ops config_d_ops;
  451. extern struct shim_fs_ops proc_fs_ops;
  452. extern struct shim_d_ops proc_d_ops;
  453. extern struct shim_mount chroot_builtin_fs;
  454. extern struct shim_mount pipe_builtin_fs;
  455. extern struct shim_mount socket_builtin_fs;
  456. extern struct shim_mount epoll_builtin_fs;
  457. /* proc file system */
  458. struct proc_nm_ops {
  459. int (*match_name) (const char * name);
  460. int (*list_name) (const char * name, struct shim_dirent ** buf,
  461. int count);
  462. };
  463. struct proc_fs_ops {
  464. int (*open) (struct shim_handle * hdl, const char * name, int flags);
  465. int (*mode) (const char * name, mode_t * mode);
  466. int (*stat) (const char * name, struct stat * buf);
  467. int (*follow_link) (const char * name, struct shim_qstr * link);
  468. };
  469. struct proc_dir;
  470. struct proc_ent {
  471. const char * name; /* a proc_callback should at least
  472. have a name or nm_ops.
  473. Otherwise, it is a NULL-end. */
  474. const struct proc_nm_ops * nm_ops;
  475. const struct proc_fs_ops * fs_ops;
  476. const struct proc_dir * dir;
  477. };
  478. struct proc_dir {
  479. int size;
  480. const struct proc_ent ent[];
  481. };
  482. /* string-type file system */
  483. int str_add_dir (const char * path, mode_t mode, struct shim_dentry ** dent);
  484. int str_add_file (const char * path, mode_t mode, struct shim_dentry ** dent);
  485. int str_open (struct shim_handle * hdl, struct shim_dentry * dent, int flags);
  486. int str_dput (struct shim_dentry * dent);
  487. int str_close (struct shim_handle * hdl);
  488. ssize_t str_read (struct shim_handle * hdl, void * buf, size_t count);
  489. ssize_t str_write (struct shim_handle * hdl, const void * buf, size_t count);
  490. off_t str_seek (struct shim_handle * hdl, off_t offset, int whence);
  491. int str_flush (struct shim_handle * hdl);
  492. #endif /* _SHIM_FS_H_ */