/** * sysfs_remove_one - remove sysfs_dirent from parent * @acxt: addrm context to use * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. * * 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(). */ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { struct sysfs_inode_attrs *ps_iattr; /* * Removal can be called multiple times on the same node. Only the * first invocation is effective and puts the base ref. */ if (sd->s_flags & SYSFS_FLAG_REMOVED) return; sysfs_unlink_sibling(sd); /* Update timestamps on the parent */ ps_iattr = sd->s_parent->s_iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; } sd->s_flags |= SYSFS_FLAG_REMOVED; sd->u.removed_list = acxt->removed; acxt->removed = sd; }
static void remove_dir(struct sysfs_dirent *sd) { struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt, sd->s_parent); sysfs_unlink_sibling(sd); sysfs_remove_one(&acxt, sd); sysfs_addrm_finish(&acxt); }
static int sysfs_dir_close(struct inode *inode, struct file *file) { struct sysfs_dirent * cursor = file->private_data; mutex_lock(&sysfs_mutex); sysfs_unlink_sibling(cursor); mutex_unlock(&sysfs_mutex); release_sysfs_dirent(cursor); return 0; }
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_remove_one - remove sysfs_dirent from parent * @acxt: addrm context to use * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. * * 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(). */ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { struct sysfs_inode_attrs *ps_iattr; BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); sysfs_unlink_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; } sd->s_flags |= SYSFS_FLAG_REMOVED; sd->s_sibling = acxt->removed; acxt->removed = sd; }
static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) { struct dentry * dentry = file->f_path.dentry; switch (origin) { case 1: offset += file->f_pos; case 0: if (offset >= 0) break; default: return -EINVAL; } if (offset != file->f_pos) { mutex_lock(&sysfs_mutex); file->f_pos = offset; if (file->f_pos >= 2) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *cursor = file->private_data; struct sysfs_dirent **pos; loff_t n = file->f_pos - 2; sysfs_unlink_sibling(cursor); pos = &sd->s_children; while (n && *pos) { struct sysfs_dirent *next = *pos; if (sysfs_type(next)) n--; pos = &(*pos)->s_sibling; } cursor->s_sibling = *pos; *pos = cursor; } mutex_unlock(&sysfs_mutex); } return offset; }
int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) { struct sysfs_dirent *sd = kobj->sd; struct sysfs_dirent *new_parent_sd; struct dentry *old_parent, *new_parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; int error; BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; /* get dentries */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); goto out_dput; } old_parent = sd->s_parent->s_dentry; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); goto out_dput; } if (old_parent->d_inode == new_parent->d_inode) { error = 0; goto out_dput; /* nothing to move */ } again: mutex_lock(&old_parent->d_inode->i_mutex); if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { mutex_unlock(&old_parent->d_inode->i_mutex); goto again; } new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; } else error = 0; d_add(new_dentry, NULL); d_move(sd->s_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ mutex_lock(&sysfs_mutex); sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); mutex_unlock(&sysfs_mutex); out_unlock: mutex_unlock(&new_parent->d_inode->i_mutex); mutex_unlock(&old_parent->d_inode->i_mutex); out_dput: dput(new_parent); dput(old_dentry); dput(new_dentry); return error; }
int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, const char *new_name) { struct sysfs_dirent *sd = kobj->sd; struct dentry *new_parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; const char *dup_name = NULL; int error; /* get dentries */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); goto out_dput; } new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); goto out_dput; } /* lock new_parent and get dentry for new name */ mutex_lock(&new_parent->d_inode->i_mutex); new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; } /* By allowing two different directories with the same * d_parent we allow this routine to move between different * shadows of the same directory */ error = -EINVAL; if (old_dentry->d_parent->d_inode != new_parent->d_inode || new_dentry->d_parent->d_inode != new_parent->d_inode || old_dentry == new_dentry) goto out_unlock; error = -EEXIST; if (new_dentry->d_inode) goto out_unlock; /* rename kobject and sysfs_dirent */ error = -ENOMEM; new_name = dup_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) goto out_drop; error = kobject_set_name(kobj, "%s", new_name); if (error) goto out_drop; mutex_lock(&sysfs_mutex); dup_name = sd->s_name; sd->s_name = new_name; /* move under the new parent */ d_add(new_dentry, NULL); d_move(sd->s_dentry, new_dentry); sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); mutex_unlock(&sysfs_mutex); error = 0; goto out_unlock; out_drop: d_drop(new_dentry); out_unlock: mutex_unlock(&new_parent->d_inode->i_mutex); out_dput: kfree(dup_name); dput(new_parent); dput(old_dentry); dput(new_dentry); return error; }