void sysfs_notify(struct kobject *k, char *dir, char *attr) { struct sysfs_dirent *sd = k->sd; mutex_lock(&sysfs_mutex); if (sd && dir) sd = sysfs_find_dirent(sd, dir); if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) { struct sysfs_open_dirent *od; spin_lock(&sysfs_open_dirent_lock); od = sd->s_attr.open; if (od) { atomic_inc(&od->event); wake_up_interruptible(&od->poll); } spin_unlock(&sysfs_open_dirent_lock); } mutex_unlock(&sysfs_mutex); }
void sysfs_notify(struct kobject *k, const char *dir, const char *attr) { struct sysfs_dirent *sd = k->sd; mutex_lock(&sysfs_mutex); if (sd && dir) sd = sysfs_find_dirent(sd, dir); if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) sysfs_notify_dirent(sd); mutex_unlock(&sysfs_mutex); }
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type) { umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; sd->s_elem.attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); if (!sysfs_find_dirent(dir_sd, attr->name)) { sysfs_add_one(&acxt, sd); sysfs_link_sibling(sd); } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); return -EEXIST; } return 0; }
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, const char *name, struct sysfs_dirent **p_sd) { umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; /* allocate */ sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) return -ENOMEM; sd->s_elem.dir.kobj = kobj; /* link in */ sysfs_addrm_start(&acxt, parent_sd); if (!sysfs_find_dirent(parent_sd, name)) { sysfs_add_one(&acxt, sd); sysfs_link_sibling(sd); } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); return -EEXIST; } *p_sd = sd; return 0; }
/** * sysfs_hash_and_remove - find a sysfs_dirent by name and remove it * @dir_sd: parent of the target * @name: name of the sysfs_dirent to remove * @ns: namespace tag of the sysfs_dirent to remove * * Look for the sysfs_dirent with @name and @ns under @dir_sd and remove * it. Returns 0 on success, -ENOENT if such entry doesn't exist. */ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, const void *ns) { struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; if (!dir_sd) { WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", name); return -ENOENT; } sysfs_addrm_start(&acxt); sd = sysfs_find_dirent(dir_sd, name, ns); if (sd) __sysfs_remove(&acxt, sd); sysfs_addrm_finish(&acxt); if (sd) return 0; else return -ENOENT; }
void sysfs_notify(struct kobject *k, char *dir, char *attr) { struct sysfs_dirent *sd = k->sd; mutex_lock(&sysfs_mutex); if (sd && dir) sd = sysfs_find_dirent(sd, dir); if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) { atomic_inc(&sd->s_event); wake_up_interruptible(&k->poll); } mutex_unlock(&sysfs_mutex); }
void sysfs_notify(struct kobject *k, const char *dir, const char *attr) { struct sysfs_dirent *sd = k->sd; mutex_lock(&sysfs_mutex); if (sd && dir) /* Only directories are tagged, so no need to pass * a tag explicitly. */ sd = sysfs_find_dirent(sd, NULL, dir); if (sd && attr) sd = sysfs_find_dirent(sd, NULL, attr); if (sd) sysfs_notify_dirent(sd); mutex_unlock(&sysfs_mutex); }
/** * sysfs_get_dirent - find and get sysfs_dirent with the given name * @parent_sd: sysfs_dirent to search under * @name: name to look for * * Look for sysfs_dirent with name @name under @parent_sd and get * it if found. * * LOCKING: * Kernel thread context (may sleep). Grabs sysfs_mutex. * * RETURNS: * Pointer to sysfs_dirent if found, NULL if not. */ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) { struct sysfs_dirent *sd; mutex_lock(&sysfs_mutex); sd = sysfs_find_dirent(parent_sd, name); sysfs_get(sd); mutex_unlock(&sysfs_mutex); return sd; }
int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, const char *new_name, const void *new_ns) { int error; mutex_lock(&sysfs_mutex); error = 0; if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) && (strcmp(sd->s_name, new_name) == 0)) goto out; /* nothing to rename */ error = -EEXIST; if (sysfs_find_dirent(new_parent_sd, new_name, new_ns)) goto out; /* rename sysfs_dirent */ if (strcmp(sd->s_name, new_name) != 0) { error = -ENOMEM; new_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) goto out; kfree(sd->s_name); sd->s_name = new_name; } /* * Move to the appropriate place in the appropriate directories rbtree. */ sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_ns = new_ns; sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); error = 0; out: mutex_unlock(&sysfs_mutex); return error; }
int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, const char *new_name) { const char *dup_name = NULL; int error; mutex_lock(&sysfs_mutex); error = 0; if ((sd->s_parent == new_parent_sd) && (strcmp(sd->s_name, new_name) == 0)) goto out; /* nothing to rename */ error = -EEXIST; if (sysfs_find_dirent(new_parent_sd, new_name)) goto out; /* rename sysfs_dirent */ if (strcmp(sd->s_name, new_name) != 0) { error = -ENOMEM; new_name = dup_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) goto out; dup_name = sd->s_name; sd->s_name = new_name; } /* Remove from old parent's list and insert into new parent's list. */ if (sd->s_parent != new_parent_sd) { sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); } error = 0; out: mutex_unlock(&sysfs_mutex); kfree(dup_name); return error; }
/** * __sysfs_add_one - add sysfs_dirent to parent without warning * @acxt: addrm context to use * @sd: sysfs_dirent to be added * * Get @acxt->parent_sd and set sd->s_parent to it and increment * nlink of parent inode if @sd is a directory and link into the * children list of the parent. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be * passed the same @acxt as passed to sysfs_addrm_start(). * * LOCKING: * Determined by sysfs_addrm_start(). * * RETURNS: * 0 on success, -EEXIST if entry with the given name already * exists. */ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { struct sysfs_inode_attrs *ps_iattr; if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) return -EEXIST; sd->s_parent = sysfs_get(acxt->parent_sd); sysfs_link_sibling(sd); /* Update timestamps on the parent */ ps_iattr = acxt->parent_sd->s_iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; } return 0; }
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; if (!dir_sd) return -ENOENT; sysfs_addrm_start(&acxt, dir_sd); sd = sysfs_find_dirent(dir_sd, name); if (sd) sysfs_remove_one(&acxt, sd); sysfs_addrm_finish(&acxt); if (sd) return 0; else return -ENOENT; }
int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) { struct sysfs_dirent *sd; struct iattr newattrs; int rc; mutex_lock(&sysfs_mutex); rc = -ENOENT; sd = sysfs_find_dirent(kobj->sd, NULL, attr->name); if (!sd) goto out; newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE; rc = sysfs_sd_setattr(sd, &newattrs); out: mutex_unlock(&sysfs_mutex); return rc; }
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; struct sysfs_dirent *sd; struct inode *inode; mutex_lock(&sysfs_mutex); sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); /* no such entry */ if (!sd) { ret = ERR_PTR(-ENOENT); goto out_unlock; } /* attach dentry and inode */ inode = sysfs_get_inode(dir->i_sb, sd); if (!inode) { ret = ERR_PTR(-ENOMEM); goto out_unlock; } /* instantiate and hash dentry */ ret = d_find_alias(inode); if (!ret) { dentry->d_op = &sysfs_dentry_ops; dentry->d_fsdata = sysfs_get(sd); d_add(dentry, inode); } else { d_move(ret, dentry); iput(inode); } out_unlock: mutex_unlock(&sysfs_mutex); return ret; }
static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct dentry *ret = NULL; struct dentry *parent = dentry->d_parent; struct sysfs_dirent *parent_sd = parent->d_fsdata; struct sysfs_dirent *sd; struct inode *inode; enum kobj_ns_type type; const void *ns; mutex_lock(&sysfs_mutex); type = sysfs_ns_type(parent_sd); ns = sysfs_info(dir->i_sb)->ns[type]; sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); /* no such entry */ if (!sd) { ret = ERR_PTR(-ENOENT); goto out_unlock; } dentry->d_fsdata = sysfs_get(sd); /* attach dentry and inode */ inode = sysfs_get_inode(dir->i_sb, sd); if (!inode) { ret = ERR_PTR(-ENOMEM); goto out_unlock; } /* instantiate and hash dentry */ ret = d_materialise_unique(dentry, inode); out_unlock: mutex_unlock(&sysfs_mutex); return ret; }