+int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
+{
+ struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry;
+ struct sysfs_dirent *new_parent_sd, *sd;
+ int error;
+
+ if (!new_parent)
+ return -EINVAL;
+
+ old_parent_dentry = kobj->parent ?
+ kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
+ new_parent_dentry = new_parent->dentry;
+
+again:
+ mutex_lock(&old_parent_dentry->d_inode->i_mutex);
+ if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
+ mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
+ goto again;
+ }
+
+ new_parent_sd = new_parent_dentry->d_fsdata;
+ sd = kobj->dentry->d_fsdata;
+
+ new_dentry = lookup_one_len(kobj->name, new_parent_dentry,
+ strlen(kobj->name));
+ if (IS_ERR(new_dentry)) {
+ error = PTR_ERR(new_dentry);
+ goto out;
+ } else
+ error = 0;
+ d_add(new_dentry, NULL);
+ d_move(kobj->dentry, new_dentry);
+ dput(new_dentry);
+
+ /* Remove from old parent's list and insert into new parent's list. */
+ list_del_init(&sd->s_sibling);
+ list_add(&sd->s_sibling, &new_parent_sd->s_children);
+
+out:
+ mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
+ mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
+
+ return error;
+}
+
+static int sysfs_dir_open(struct inode *inode, struct file *file)
+{
+ struct dentry * dentry = file->f_path.dentry;
+ struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ file->private_data = sysfs_new_dirent(parent_sd, NULL);
+ mutex_unlock(&dentry->d_inode->i_mutex);
+
+ return file->private_data ? 0 : -ENOMEM;
+
+}
+
+static int sysfs_dir_close(struct inode *inode, struct file *file)
+{
+ struct dentry * dentry = file->f_path.dentry;
+ struct sysfs_dirent * cursor = file->private_data;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ list_del_init(&cursor->s_sibling);
+ mutex_unlock(&dentry->d_inode->i_mutex);
+
+ release_sysfs_dirent(cursor);
+
+ return 0;
+}
+
+/* Relationship between s_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct sysfs_dirent *sd)
+{
+ return (sd->s_mode >> 12) & 15;
+}
+
+static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_path.dentry;
+ struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+ struct sysfs_dirent *cursor = filp->private_data;
+ struct list_head *p, *q = &cursor->s_sibling;
+ ino_t ino;
+ int i = filp->f_pos;
+
+ switch (i) {
+ case 0:
+ ino = dentry->d_inode->i_ino;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+ break;
+ filp->f_pos++;
+ i++;
+ /* fallthrough */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+ break;
+ filp->f_pos++;
+ i++;
+ /* fallthrough */
+ default:
+ if (filp->f_pos == 2)
+ list_move(q, &parent_sd->s_children);
+
+ for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
+ struct sysfs_dirent *next;
+ const char * name;
+ int len;
+
+ next = list_entry(p, struct sysfs_dirent,
+ s_sibling);
+ if (!next->s_element)
+ continue;
+
+ name = sysfs_get_name(next);
+ len = strlen(name);
+ if (next->s_dentry)
+ ino = next->s_dentry->d_inode->i_ino;
+ else
+ ino = iunique(sysfs_sb, 2);
+
+ if (filldir(dirent, name, len, filp->f_pos, ino,
+ dt_type(next)) < 0)
+ return 0;
+
+ list_move(q, p);
+ p = q;
+ filp->f_pos++;
+ }
+ }
+ return 0;
+}
+
+static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
+{
+ struct dentry * dentry = file->f_path.dentry;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ case 0:
+ if (offset >= 0)
+ break;
+ default:
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
+ return -EINVAL;
+ }
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ if (file->f_pos >= 2) {
+ struct sysfs_dirent *sd = dentry->d_fsdata;
+ struct sysfs_dirent *cursor = file->private_data;
+ struct list_head *p;
+ loff_t n = file->f_pos - 2;
+
+ list_del(&cursor->s_sibling);
+ p = sd->s_children.next;
+ while (n && p != &sd->s_children) {
+ struct sysfs_dirent *next;
+ next = list_entry(p, struct sysfs_dirent,
+ s_sibling);
+ if (next->s_element)
+ n--;
+ p = p->next;
+ }
+ list_add_tail(&cursor->s_sibling, p);
+ }
+ }
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ return offset;
+}