summaryrefslogtreecommitdiff
path: root/usr/src/cmd/devfsadm/devfsadm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/devfsadm/devfsadm.c')
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c150
1 files changed, 144 insertions, 6 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c
index c1ffa5e1aa..1053dd8776 100644
--- a/usr/src/cmd/devfsadm/devfsadm.c
+++ b/usr/src/cmd/devfsadm/devfsadm.c
@@ -207,6 +207,10 @@ static int login_dev_enable = FALSE;
/* Global to use devinfo snapshot cache */
static int use_snapshot_cache = FALSE;
+/* Global for no-further-processing hash */
+static item_t **nfp_hash;
+static mutex_t nfp_mutex = DEFAULTMUTEX;
+
/*
* Packaged directories - not removed even when empty.
* The dirs must be listed in canonical form
@@ -391,6 +395,7 @@ update_drvconf(major_t major)
major);
}
+
static void
load_dev_acl()
{
@@ -2037,7 +2042,7 @@ static void
load_module(char *mname, char *cdir)
{
_devfsadm_create_reg_t *create_reg;
- _devfsadm_remove_reg_t *remove_reg;
+ _devfsadm_remove_reg_V1_t *remove_reg;
create_list_t *create_list_element;
create_list_t **create_list_next;
remove_list_t *remove_list_element;
@@ -2047,6 +2052,7 @@ load_module(char *mname, char *cdir)
char *dlerrstr;
void *dlhandle;
module_t *module;
+ int flags;
int n;
int i;
@@ -2079,7 +2085,7 @@ load_module(char *mname, char *cdir)
}
/* dlsym the _devfsadm_remove_reg structure */
- if (NULL == (remove_reg = (_devfsadm_remove_reg_t *)
+ if (NULL == (remove_reg = (_devfsadm_remove_reg_V1_t *)
dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) {
vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n",
epath, _DEVFSADM_REMOVE_REG);
@@ -2220,13 +2226,17 @@ load_module(char *mname, char *cdir)
* put a ptr to each struct devfsadm_remove on "remove_head"
* list sorted by interpose_lvl.
*/
+ flags = 0;
if (remove_reg != NULL) {
+ if (remove_reg->version < DEVFSADM_V1)
+ flags |= RM_NOINTERPOSE;
for (i = 0; i < remove_reg->count; i++) {
remove_list_element = (remove_list_t *)
s_malloc(sizeof (remove_list_t));
remove_list_element->remove = &(remove_reg->tblp[i]);
+ remove_list_element->remove->flags |= flags;
remove_list_element->modptr = module;
for (remove_list_next = &(remove_head);
@@ -4004,6 +4014,9 @@ pre_and_post_cleanup(int flags)
rd.data = (void *)&cleanup_data;
cleanup_data.flags = flags;
+ (void) mutex_lock(&nfp_mutex);
+ nfphash_create();
+
for (rm = remove_head; rm != NULL; rm = rm->next) {
if ((flags & rm->remove->flags) == flags) {
cleanup_data.rm = rm;
@@ -4020,6 +4033,8 @@ pre_and_post_cleanup(int flags)
}
}
}
+ nfphash_destroy();
+ (void) mutex_unlock(&nfp_mutex);
}
/*
@@ -4044,7 +4059,7 @@ pre_and_post_cleanup(int flags)
*
*/
static int
-clean_ok(devfsadm_remove_t *remove)
+clean_ok(devfsadm_remove_V1_t *remove)
{
int i;
@@ -4103,6 +4118,7 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass,
char rmlink[PATH_MAX + 1];
nvlist_t *nvl = NULL;
int skip;
+ int ret;
/*
* dev links can go away as part of hot cleanup.
@@ -4120,6 +4136,9 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass,
vprint(REMOVE_MID, "%spath=%s\n", fcn, path);
+ (void) mutex_lock(&nfp_mutex);
+ nfphash_create();
+
for (rm = remove_head; rm != NULL; rm = rm->next) {
if ((RM_HOT & rm->remove->flags) == RM_HOT) {
head = get_cached_links(rm->remove->dev_dirs_re);
@@ -4137,6 +4156,14 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass,
* the next valid link.
*/
head->nextlink = link->next;
+
+ /*
+ * if devlink is in no-further-process hash,
+ * skip its remove
+ */
+ if (nfphash_lookup(link->devlink) != NULL)
+ continue;
+
if (minor_name)
skip = strcmp(link->contents, path);
else
@@ -4157,11 +4184,22 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass,
*/
(void) snprintf(rmlink, sizeof (rmlink),
"%s", link->devlink);
- (*(rm->remove->callback_fcn))(rmlink);
+ if (rm->remove->flags & RM_NOINTERPOSE) {
+ ((void (*)(char *))
+ (rm->remove->callback_fcn))(rmlink);
+ } else {
+ ret = ((int (*)(char *))
+ (rm->remove->callback_fcn))(rmlink);
+ if (ret == DEVFSADM_TERMINATE)
+ nfphash_insert(rmlink);
+ }
}
}
}
+ nfphash_destroy();
+ (void) mutex_unlock(&nfp_mutex);
+
/* update device allocation database */
if (system_labeled) {
int ret = 0;
@@ -4263,22 +4301,44 @@ static void
matching_dev(char *devpath, void *data)
{
cleanup_data_t *cleanup_data = data;
+ int norm_len = strlen(dev_dir) + strlen("/");
+ int ret;
char *fcn = "matching_dev: ";
vprint(RECURSEDEV_MID, "%sexamining devpath = '%s'\n", fcn,
devpath);
+ /*
+ * If the link is in the no-further-process hash
+ * don't do any remove operation on it.
+ */
+ if (nfphash_lookup(devpath + norm_len) != NULL)
+ return;
+
if (resolve_link(devpath, NULL, NULL, NULL, 1) == TRUE) {
if (call_minor_init(cleanup_data->rm->modptr) ==
DEVFSADM_FAILURE) {
return;
}
- devpath += strlen(dev_dir) + strlen("/");
+ devpath += norm_len;
vprint(RECURSEDEV_MID, "%scalling"
" callback %s\n", fcn, devpath);
- (*(cleanup_data->rm->remove->callback_fcn))(devpath);
+ if (cleanup_data->rm->remove->flags & RM_NOINTERPOSE)
+ ((void (*)(char *))
+ (cleanup_data->rm->remove->callback_fcn))(devpath);
+ else {
+ ret = ((int (*)(char *))
+ (cleanup_data->rm->remove->callback_fcn))(devpath);
+ if (ret == DEVFSADM_TERMINATE) {
+ /*
+ * We want no further remove processing for
+ * this link. Add it to the nfp_hash;
+ */
+ nfphash_insert(devpath);
+ }
+ }
}
}
@@ -8043,6 +8103,84 @@ is_blank(char *line)
return (1);
}
+/*
+ * Functions to deal with the no-further-processing hash
+ */
+
+static void
+nfphash_create(void)
+{
+ assert(nfp_hash == NULL);
+ nfp_hash = s_zalloc(NFP_HASH_SZ * sizeof (item_t *));
+}
+
+static int
+nfphash_fcn(char *key)
+{
+ int i;
+ uint64_t sum = 0;
+
+ for (i = 0; key[i] != '\0'; i++) {
+ sum += (uchar_t)key[i];
+ }
+
+ return (sum % NFP_HASH_SZ);
+}
+
+static item_t *
+nfphash_lookup(char *key)
+{
+ int index;
+ item_t *ip;
+
+ index = nfphash_fcn(key);
+
+ assert(index >= 0);
+
+ for (ip = nfp_hash[index]; ip; ip = ip->i_next) {
+ if (strcmp(ip->i_key, key) == 0)
+ return (ip);
+ }
+
+ return (NULL);
+}
+
+static void
+nfphash_insert(char *key)
+{
+ item_t *ip;
+ int index;
+
+ index = nfphash_fcn(key);
+
+ assert(index >= 0);
+
+ ip = s_zalloc(sizeof (item_t));
+ ip->i_key = s_strdup(key);
+
+ ip->i_next = nfp_hash[index];
+ nfp_hash[index] = ip;
+}
+
+static void
+nfphash_destroy(void)
+{
+ int i;
+ item_t *ip;
+
+ for (i = 0; i < NFP_HASH_SZ; i++) {
+ /*LINTED*/
+ while (ip = nfp_hash[i]) {
+ nfp_hash[i] = ip->i_next;
+ free(ip->i_key);
+ free(ip);
+ }
+ }
+
+ free(nfp_hash);
+ nfp_hash = NULL;
+}
+
static int
devname_kcall(int subcmd, void *args)
{