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