WIP-pop-3000
[akaros.git] / kern / include / fs_file.h
index 00e6046..9b4f06a 100644 (file)
  * ------------------
  * Note this qlock is also used by tree_file code.  See below for details.
  *
- * Hold the qlock when changing the contents of a file.  This includes writes
- * (which need to adjust the len and add data), truncate / hole-punches
- * (which need to adjust the len and remove data), changing parts of dir (name,
- * permissions/mode, atimes), etc.  Tree files will hold this qlock when
- * changing a parent's children.
+ * 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
  * into other issues).  'name' is somewhat special: if you find the tree_file
  * via a RCU protected wc hash lookup, you can access name.
  *
- * fs_file_read() can skip the qlock in the common case.  It can try to grab a
- * page from the PM (if it was there, then some ordering exists on the
- * concurrent ops where the read partially succeeds).  If the read fails to find
- * a page, then we'd need to lock, since that interacts with length.
- *
  * 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
  * chown will work.
  *
  * Note that even if we can atomically write to the dir, we should still grab
- * the qlock.  The reason is that there may be readers who want to make sure
- * parts of the dir doesn't change.
+ * 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:
- * - Hole punching / truncate:  pm_remove_contig() leaves behind pages if they
- *   were concurrently opened.  We can't detach from the tree since the pm_page
- *   assumes it is always hooked in.  This means a truncate during a read or
- *   mmap could leave data behind in the PM, which will be accessible when len
- *   gets increased again (e.g. seek and write).  Truncate could zero that page,
- *   though we'd need a history counter so reads don't see a partial value.
- *   Further, pinned VMRs get skipped.  During trunc, they should get removed
- *   and generate a SIGBUS on access.
  * - 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.
@@ -115,6 +102,11 @@ 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);