summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/vnode.h
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/sys/vnode.h')
-rw-r--r--usr/src/uts/common/sys/vnode.h74
1 files changed, 70 insertions, 4 deletions
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index e4d43cea7f..c779cc1ff6 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -221,6 +221,59 @@ struct vsd_node {
* In particular, file systems should not access other fields; they may
* change or even be removed. The functionality which was once provided
* by these fields is available through vn_* functions.
+ *
+ * VNODE PATH THEORY:
+ * In each vnode, the v_path field holds a cached version of the canonical
+ * filesystem path which that node represents. Because vnodes lack contextual
+ * information about their own name or position in the VFS hierarchy, this path
+ * must be calculated when the vnode is instantiated by operations such as
+ * fop_create, fop_lookup, or fop_mkdir. During said operations, both the
+ * parent vnode (and its cached v_path) and future name are known, so the
+ * v_path of the resulting object can easily be set.
+ *
+ * The caching nature of v_path is complicated in the face of directory
+ * renames. Filesystem drivers are responsible for calling vn_renamepath when
+ * a fop_rename operation succeeds. While the v_path on the renamed vnode will
+ * be updated, existing children of the directory (direct, or at deeper levels)
+ * will now possess v_path caches which are stale.
+ *
+ * It is expensive (and for non-directories, impossible) to recalculate stale
+ * v_path entries during operations such as vnodetopath. The best time during
+ * which to correct such wrongs is the same as when v_path is first
+ * initialized: during fop_create/fop_lookup/fop_mkdir/etc, where adequate
+ * context is available to generate the current path.
+ *
+ * In order to quickly detect stale v_path entries (without full lookup
+ * verification) to trigger a v_path update, the v_path_stamp field has been
+ * added to vnode_t. As part of successful fop_create/fop_lookup/fop_mkdir
+ * operations, where the name and parent vnode are available, the following
+ * rules are used to determine updates to the child:
+ *
+ * 1. If the parent lacks a v_path, clear any existing v_path and v_path_stamp
+ * on the child. Until the parent v_path is refreshed to a valid state, the
+ * child v_path must be considered invalid too.
+ *
+ * 2. If the child lacks a v_path (implying v_path_stamp == 0), it inherits the
+ * v_path_stamp value from its parent and its v_path is updated.
+ *
+ * 3. If the child v_path_stamp is less than v_path_stamp in the parent, it is
+ * an indication that the child v_path is stale. The v_path is updated and
+ * v_path_stamp in the child is set to the current hrtime().
+ *
+ * It does _not_ inherit the parent v_path_stamp in order to propagate the
+ * the time of v_path invalidation through the directory structure. This
+ * prevents concurrent invalidations (operating with a now-incorrect v_path)
+ * at deeper levels in the tree from persisting.
+ *
+ * 4. If the child v_path_stamp is greater or equal to the parent, no action
+ * needs to be taken.
+ *
+ * Note that fop_rename operations do not follow this ruleset. They perform an
+ * explicit update of v_path and v_path_stamp (setting it to the current time)
+ *
+ * With these constraints in place, v_path invalidations and updates should
+ * proceed in a timely manner as vnodes are accessed. While there still are
+ * limited cases where vnodetopath operations will fail, the risk is minimized.
*/
struct fem_head; /* from fem.h */
@@ -247,6 +300,7 @@ typedef struct vnode {
void *v_locality; /* hook for locality info */
struct fem_head *v_femhead; /* fs monitoring */
char *v_path; /* cached path */
+ hrtime_t v_path_stamp; /* timestamp for cached path */
uint_t v_rdcnt; /* open for read count (VREG only) */
uint_t v_wrcnt; /* open for write count (VREG only) */
u_longlong_t v_mmap_read; /* mmap read count */
@@ -738,12 +792,14 @@ typedef enum vnevent {
VE_RMDIR = 4, /* Remove of directory vnode's name */
VE_CREATE = 5, /* Create with vnode's name which exists */
VE_LINK = 6, /* Link with vnode's name as source */
- VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
+ VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
VE_TRUNCATE = 9, /* Truncate */
VE_PRE_RENAME_SRC = 10, /* Pre-rename, with vnode as source */
VE_PRE_RENAME_DEST = 11, /* Pre-rename, with vnode as target/dest. */
- VE_PRE_RENAME_DEST_DIR = 12 /* Pre-rename with vnode as target dir */
+ VE_PRE_RENAME_DEST_DIR = 12, /* Pre-rename with vnode as target dir */
+ VE_RENAME_SRC_DIR = 13, /* Rename with vnode as source dir */
+ VE_RESIZE = 14 /* Resize/truncate to non-zero offset */
} vnevent_t;
/*
@@ -1291,6 +1347,11 @@ void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
const char *path, size_t plen);
void vn_renamepath(vnode_t *dvp, vnode_t *vp, const char *nm, size_t len);
+/* Private vnode manipulation functions */
+void vn_clearpath(vnode_t *, hrtime_t);
+void vn_updatepath(vnode_t *, vnode_t *, const char *);
+
+
/* Vnode event notification */
void vnevent_rename_src(vnode_t *, vnode_t *, char *, caller_context_t *);
void vnevent_rename_dest(vnode_t *, vnode_t *, char *, caller_context_t *);
@@ -1298,7 +1359,8 @@ void vnevent_remove(vnode_t *, vnode_t *, char *, caller_context_t *);
void vnevent_rmdir(vnode_t *, vnode_t *, char *, caller_context_t *);
void vnevent_create(vnode_t *, caller_context_t *);
void vnevent_link(vnode_t *, caller_context_t *);
-void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
+void vnevent_rename_dest_dir(vnode_t *, vnode_t *, char *,
+ caller_context_t *ct);
void vnevent_mountedover(vnode_t *, caller_context_t *);
void vnevent_truncate(vnode_t *, caller_context_t *);
int vnevent_support(vnode_t *, caller_context_t *);
@@ -1308,6 +1370,7 @@ void vnevent_pre_rename_dest(vnode_t *, vnode_t *, char *,
caller_context_t *);
void vnevent_pre_rename_dest_dir(vnode_t *, vnode_t *, char *,
caller_context_t *);
+void vnevent_resize(vnode_t *, caller_context_t *);
/* Vnode specific data */
void vsd_create(uint_t *, void (*)(void *));
@@ -1337,6 +1400,9 @@ u_longlong_t fs_new_caller_id();
int vn_vmpss_usepageio(vnode_t *);
+/* Empty v_path placeholder */
+extern char *vn_vpath_empty;
+
/*
* Needed for use of IS_VMODSORT() in kernel.
*/