Print this page
*** 148,157 ****
--- 148,163 ----
};
kmem_cache_t *sdev_node_cache; /* sdev_node cache */
int devtype; /* fstype */
+ /* static */
+ static struct vnodeops *sdev_get_vop(struct sdev_node *);
+ static void sdev_set_no_negcache(struct sdev_node *);
+ static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []);
+ static void sdev_free_vtab(fs_operation_def_t *);
+
static void
sdev_prof_free(struct sdev_node *dv)
{
ASSERT(!SDEV_IS_GLOBAL(dv));
nvlist_free(dv->sdev_prof.dev_name);
*** 305,315 ****
len = strlen(ddv->sdev_path) + strlen(nm) + 2;
dv->sdev_path = kmem_alloc(len, KM_SLEEP);
(void) snprintf(dv->sdev_path, len, "%s/%s", ddv->sdev_path, nm);
/* overwritten for VLNK nodes */
dv->sdev_symlink = NULL;
- list_link_init(&dv->sdev_plist);
vp = SDEVTOV(dv);
vn_reinit(vp);
vp->v_vfsp = SDEVTOV(ddv)->v_vfsp;
if (vap)
--- 311,320 ----
*** 394,404 ****
dv->sdev_nlink = 1;
dv->sdev_symlink = i_ddi_strdup((char *)args, KM_SLEEP);
} else {
dv->sdev_nlink = 1;
}
- sdev_plugin_nodeready(dv);
if (!(SDEV_IS_GLOBAL(dv))) {
dv->sdev_origin = (struct sdev_node *)args;
dv->sdev_flags &= ~SDEV_PERSIST;
}
--- 399,408 ----
*** 491,516 ****
rw_exit(&dv->sdev_contents);
sdev_nc_node_exists(dv);
return (dv);
}
! struct sdev_vop_table vtab[] = {
! { "pts", devpts_vnodeops_tbl, &devpts_vnodeops, devpts_validate,
SDEV_DYNAMIC | SDEV_VTOR },
! { "vt", devvt_vnodeops_tbl, &devvt_vnodeops, devvt_validate,
SDEV_DYNAMIC | SDEV_VTOR },
! { "zvol", devzvol_vnodeops_tbl, &devzvol_vnodeops,
devzvol_validate, SDEV_ZONED | SDEV_DYNAMIC | SDEV_VTOR | SDEV_SUBDIR },
! { "zcons", NULL, NULL, NULL, SDEV_NO_NCACHE },
! { "net", devnet_vnodeops_tbl, &devnet_vnodeops, devnet_validate,
! SDEV_DYNAMIC | SDEV_VTOR | SDEV_SUBDIR },
! { "ipnet", devipnet_vnodeops_tbl, &devipnet_vnodeops,
devipnet_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_NO_NCACHE },
/*
* SDEV_DYNAMIC: prevent calling out to devfsadm, since only the
* lofi driver controls child nodes.
--- 495,535 ----
rw_exit(&dv->sdev_contents);
sdev_nc_node_exists(dv);
return (dv);
}
! /* directory dependent vop table */
! struct sdev_vop_table {
! char *vt_name; /* subdirectory name */
! const fs_operation_def_t *vt_service; /* vnodeops table */
! struct vnodeops *vt_vops; /* constructed vop */
! struct vnodeops **vt_global_vops; /* global container for vop */
! int (*vt_vtor)(struct sdev_node *); /* validate sdev_node */
! int vt_flags;
! };
!
! /*
! * A nice improvement would be to provide a plug-in mechanism
! * for this table instead of a const table.
! */
! static struct sdev_vop_table vtab[] =
! {
! { "pts", devpts_vnodeops_tbl, NULL, &devpts_vnodeops, devpts_validate,
SDEV_DYNAMIC | SDEV_VTOR },
! { "vt", devvt_vnodeops_tbl, NULL, &devvt_vnodeops, devvt_validate,
SDEV_DYNAMIC | SDEV_VTOR },
! { "zvol", devzvol_vnodeops_tbl, NULL, &devzvol_vnodeops,
devzvol_validate, SDEV_ZONED | SDEV_DYNAMIC | SDEV_VTOR | SDEV_SUBDIR },
! { "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE },
! { "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate,
! SDEV_DYNAMIC | SDEV_VTOR },
! { "ipnet", devipnet_vnodeops_tbl, NULL, &devipnet_vnodeops,
devipnet_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_NO_NCACHE },
/*
* SDEV_DYNAMIC: prevent calling out to devfsadm, since only the
* lofi driver controls child nodes.
*** 521,540 ****
* In addition, devfsadm knows not to attempt a rmdir: a zone
* may hold a reference, which would zombify the node,
* preventing a mkdir.
*/
! { "lofi", NULL, NULL, NULL,
SDEV_ZONED | SDEV_DYNAMIC | SDEV_PERSIST },
! { "rlofi", NULL, NULL, NULL,
SDEV_ZONED | SDEV_DYNAMIC | SDEV_PERSIST },
! { NULL, NULL, NULL, NULL, 0}
};
/*
* Build the base root inode
*/
ino_t
sdev_mkino(struct sdev_node *dv)
{
--- 540,677 ----
* In addition, devfsadm knows not to attempt a rmdir: a zone
* may hold a reference, which would zombify the node,
* preventing a mkdir.
*/
! { "lofi", NULL, NULL, NULL, NULL,
SDEV_ZONED | SDEV_DYNAMIC | SDEV_PERSIST },
! { "rlofi", NULL, NULL, NULL, NULL,
SDEV_ZONED | SDEV_DYNAMIC | SDEV_PERSIST },
! { NULL, NULL, NULL, NULL, NULL, 0}
};
+ /*
+ * We need to match off of the sdev_path, not the sdev_name. We are only allowed
+ * to exist directly under /dev.
+ */
+ struct sdev_vop_table *
+ sdev_match(struct sdev_node *dv)
+ {
+ int vlen;
+ int i;
+ const char *path;
+ if (strlen(dv->sdev_path) <= 5)
+ return (NULL);
+
+ if (strncmp(dv->sdev_path, "/dev/", 5) != 0)
+ return (NULL);
+ path = dv->sdev_path + 5;
+
+ for (i = 0; vtab[i].vt_name; i++) {
+ if (strcmp(vtab[i].vt_name, path) == 0)
+ return (&vtab[i]);
+ if (vtab[i].vt_flags & SDEV_SUBDIR) {
+ vlen = strlen(vtab[i].vt_name);
+ if ((strncmp(vtab[i].vt_name, path,
+ vlen - 1) == 0) && path[vlen] == '/')
+ return (&vtab[i]);
+ }
+
+ }
+ return (NULL);
+ }
+
/*
+ * sets a directory's vnodeops if the directory is in the vtab;
+ */
+ static struct vnodeops *
+ sdev_get_vop(struct sdev_node *dv)
+ {
+ struct sdev_vop_table *vtp;
+ char *path;
+
+ path = dv->sdev_path;
+ ASSERT(path);
+
+ /* gets the relative path to /dev/ */
+ path += 5;
+
+ /* gets the vtab entry it matches */
+ if ((vtp = sdev_match(dv)) != NULL) {
+ dv->sdev_flags |= vtp->vt_flags;
+ if (SDEV_IS_PERSIST(dv->sdev_dotdot) &&
+ (SDEV_IS_PERSIST(dv) || !SDEV_IS_DYNAMIC(dv)))
+ dv->sdev_flags |= SDEV_PERSIST;
+
+ if (vtp->vt_vops) {
+ if (vtp->vt_global_vops)
+ *(vtp->vt_global_vops) = vtp->vt_vops;
+
+ return (vtp->vt_vops);
+ }
+
+ if (vtp->vt_service) {
+ fs_operation_def_t *templ;
+ templ = sdev_merge_vtab(vtp->vt_service);
+ if (vn_make_ops(vtp->vt_name,
+ (const fs_operation_def_t *)templ,
+ &vtp->vt_vops) != 0) {
+ cmn_err(CE_PANIC, "%s: malformed vnode ops\n",
+ vtp->vt_name);
+ /*NOTREACHED*/
+ }
+ if (vtp->vt_global_vops) {
+ *(vtp->vt_global_vops) = vtp->vt_vops;
+ }
+ sdev_free_vtab(templ);
+
+ return (vtp->vt_vops);
+ }
+
+ return (sdev_vnodeops);
+ }
+
+ /* child inherits the persistence of the parent */
+ if (SDEV_IS_PERSIST(dv->sdev_dotdot))
+ dv->sdev_flags |= SDEV_PERSIST;
+
+ return (sdev_vnodeops);
+ }
+
+ static void
+ sdev_set_no_negcache(struct sdev_node *dv)
+ {
+ int i;
+ char *path;
+
+ ASSERT(dv->sdev_path);
+ path = dv->sdev_path + strlen("/dev/");
+
+ for (i = 0; vtab[i].vt_name; i++) {
+ if (strcmp(vtab[i].vt_name, path) == 0) {
+ if (vtab[i].vt_flags & SDEV_NO_NCACHE)
+ dv->sdev_flags |= SDEV_NO_NCACHE;
+ break;
+ }
+ }
+ }
+
+ void *
+ sdev_get_vtor(struct sdev_node *dv)
+ {
+ struct sdev_vop_table *vtp;
+
+ vtp = sdev_match(dv);
+ if (vtp)
+ return ((void *)vtp->vt_vtor);
+ else
+ return (NULL);
+ }
+
+ /*
* Build the base root inode
*/
ino_t
sdev_mkino(struct sdev_node *dv)
{
*** 808,822 ****
if (dv->sdev_path) {
kmem_free(dv->sdev_path, strlen(dv->sdev_path) + 1);
dv->sdev_path = NULL;
}
! if (!SDEV_IS_GLOBAL(dv)) {
sdev_prof_free(dv);
- if (dv->sdev_vnode->v_type != VLNK && dv->sdev_origin != NULL)
- SDEV_RELE(dv->sdev_origin);
- }
if (SDEVTOV(dv)->v_type == VDIR) {
ASSERT(SDEV_FIRST_ENTRY(dv) == NULL);
avl_destroy(&dv->sdev_entries);
}
--- 945,956 ----
if (dv->sdev_path) {
kmem_free(dv->sdev_path, strlen(dv->sdev_path) + 1);
dv->sdev_path = NULL;
}
! if (!SDEV_IS_GLOBAL(dv))
sdev_prof_free(dv);
if (SDEVTOV(dv)->v_type == VDIR) {
ASSERT(SDEV_FIRST_ENTRY(dv) == NULL);
avl_destroy(&dv->sdev_entries);
}
*** 2809,2818 ****
--- 2943,2992 ----
VN_RELE(vp);
return (error);
}
+ extern int sdev_vnodeops_tbl_size;
+
+ /*
+ * construct a new template with overrides from vtab
+ */
+ static fs_operation_def_t *
+ sdev_merge_vtab(const fs_operation_def_t tab[])
+ {
+ fs_operation_def_t *new;
+ const fs_operation_def_t *tab_entry;
+
+ /* make a copy of standard vnode ops table */
+ new = kmem_alloc(sdev_vnodeops_tbl_size, KM_SLEEP);
+ bcopy((void *)sdev_vnodeops_tbl, new, sdev_vnodeops_tbl_size);
+
+ /* replace the overrides from tab */
+ for (tab_entry = tab; tab_entry->name != NULL; tab_entry++) {
+ fs_operation_def_t *std_entry = new;
+ while (std_entry->name) {
+ if (strcmp(tab_entry->name, std_entry->name) == 0) {
+ std_entry->func = tab_entry->func;
+ break;
+ }
+ std_entry++;
+ }
+ if (std_entry->name == NULL)
+ cmn_err(CE_NOTE, "sdev_merge_vtab: entry %s unused.",
+ tab_entry->name);
+ }
+
+ return (new);
+ }
+
+ /* free memory allocated by sdev_merge_vtab */
+ static void
+ sdev_free_vtab(fs_operation_def_t *new)
+ {
+ kmem_free(new, sdev_vnodeops_tbl_size);
+ }
+
/*
* a generic setattr() function
*
* note: flags only supports AT_UID and AT_GID.
* Future enhancements can be done for other types, e.g. AT_MODE