#include <linux/idr.h>
#include <linux/completion.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
#include "sysfs.h"
DEFINE_MUTEX(sysfs_mutex);
memset(acxt, 0, sizeof(*acxt));
acxt->parent_sd = parent_sd;
- /* Lookup parent inode. inode initialization and I_NEW
- * clearing are protected by sysfs_mutex. By grabbing it and
- * looking up with _nowait variant, inode state can be
- * determined reliably.
+ /* Lookup parent inode. inode initialization is protected by
+ * sysfs_mutex, so inode existence can be determined by
+ * looking up inode while holding sysfs_mutex.
*/
mutex_lock(&sysfs_mutex);
- inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
- parent_sd);
+ inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
+ parent_sd);
+ if (inode) {
+ WARN_ON(inode->i_state & I_NEW);
- if (inode && !(inode->i_state & I_NEW)) {
/* parent inode available */
acxt->parent_inode = inode;
mutex_lock(&inode->i_mutex);
mutex_lock(&sysfs_mutex);
}
- } else
- iput(inode);
+ }
}
/**
- * sysfs_add_one - add sysfs_dirent to parent
+ * __sysfs_add_one - add sysfs_dirent to parent without warning
* @acxt: addrm context to use
* @sd: sysfs_dirent to be added
*
* 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)
+int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
- if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) {
- printk(KERN_WARNING "sysfs: duplicate filename '%s' "
- "can not be created\n", sd->s_name);
- WARN_ON(1);
+ if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
return -EEXIST;
- }
sd->s_parent = sysfs_get(acxt->parent_sd);
}
/**
+ * sysfs_add_one - add sysfs_dirent to parent
+ * @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)
+{
+ int ret;
+
+ ret = __sysfs_add_one(acxt, sd);
+ WARN(ret == -EEXIST, KERN_WARNING "sysfs: duplicate filename '%s' "
+ "can not be created\n", sd->s_name);
+ return ret;
+}
+
+/**
* sysfs_remove_one - remove sysfs_dirent from parent
* @acxt: addrm context to use
* @sd: sysfs_dirent to be removed
return sd;
}
+EXPORT_SYMBOL_GPL(sysfs_get_dirent);
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
const char *name, struct sysfs_dirent **p_sd)
if (!new_dentry)
goto out_unlock;
- /* rename kobject and sysfs_dirent */
+ /* rename sysfs_dirent */
error = -ENOMEM;
new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
goto out_unlock;
- error = kobject_set_name(kobj, "%s", new_name);
- if (error)
- goto out_unlock;
-
dup_name = sd->s_name;
sd->s_name = new_name;
const struct file_operations sysfs_dir_operations = {
.read = generic_read_dir,
.readdir = sysfs_readdir,
+ .llseek = generic_file_llseek,
};