]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/sysfs/symlink.c
sysfs: sysfs_delete_link handle symlinks from untagged to tagged directories.
[net-next-2.6.git] / fs / sysfs / symlink.c
index 942f239a2132c8b12d47c1258bb02cfbd17a2726..660383321347567a7e9cd4f0e429a1886aca2187 100644 (file)
@@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
        struct sysfs_dirent *target_sd = NULL;
        struct sysfs_dirent *sd = NULL;
        struct sysfs_addrm_cxt acxt;
+       enum kobj_ns_type ns_type;
        int error;
 
        BUG_ON(!name);
@@ -58,14 +59,28 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
        if (!sd)
                goto out_put;
 
+       ns_type = sysfs_ns_type(parent_sd);
+       if (ns_type)
+               sd->s_ns = target->ktype->namespace(target);
        sd->s_symlink.target_sd = target_sd;
        target_sd = NULL;       /* reference is now owned by the symlink */
 
        sysfs_addrm_start(&acxt, parent_sd);
-       if (warn)
-               error = sysfs_add_one(&acxt, sd);
-       else
-               error = __sysfs_add_one(&acxt, sd);
+       /* Symlinks must be between directories with the same ns_type */
+       if (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent)) {
+               if (warn)
+                       error = sysfs_add_one(&acxt, sd);
+               else
+                       error = __sysfs_add_one(&acxt, sd);
+       } else {
+               error = -EINVAL;
+               WARN(1, KERN_WARNING
+                       "sysfs: symlink across ns_types %s/%s -> %s/%s\n",
+                       parent_sd->s_name,
+                       sd->s_name,
+                       sd->s_symlink.target_sd->s_parent->s_name,
+                       sd->s_symlink.target_sd->s_name);
+       }
        sysfs_addrm_finish(&acxt);
 
        if (error)
@@ -106,6 +121,26 @@ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
        return sysfs_do_create_link(kobj, target, name, 0);
 }
 
+/**
+ *     sysfs_delete_link - remove symlink in object's directory.
+ *     @kobj:  object we're acting for.
+ *     @targ:  object we're pointing to.
+ *     @name:  name of the symlink to remove.
+ *
+ *     Unlike sysfs_remove_link sysfs_delete_link has enough information
+ *     to successfully delete symlinks in tagged directories.
+ */
+void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
+                       const char *name)
+{
+       const void *ns = NULL;
+       spin_lock(&sysfs_assoc_lock);
+       if (targ->sd && sysfs_ns_type(kobj->sd))
+               ns = targ->sd->s_ns;
+       spin_unlock(&sysfs_assoc_lock);
+       sysfs_hash_and_remove(kobj->sd, ns, name);
+}
+
 /**
  *     sysfs_remove_link - remove symlink in object's directory.
  *     @kobj:  object we're acting for.
@@ -121,7 +156,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
        else
                parent_sd = kobj->sd;
 
-       sysfs_hash_and_remove(parent_sd, name);
+       sysfs_hash_and_remove(parent_sd, NULL, name);
 }
 
 /**
@@ -137,6 +172,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
                        const char *old, const char *new)
 {
        struct sysfs_dirent *parent_sd, *sd = NULL;
+       const void *old_ns = NULL, *new_ns = NULL;
        int result;
 
        if (!kobj)
@@ -144,8 +180,11 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
        else
                parent_sd = kobj->sd;
 
+       if (targ->sd)
+               old_ns = targ->sd->s_ns;
+
        result = -ENOENT;
-       sd = sysfs_get_dirent(parent_sd, old);
+       sd = sysfs_get_dirent(parent_sd, old_ns, old);
        if (!sd)
                goto out;
 
@@ -155,7 +194,10 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
        if (sd->s_symlink.target_sd->s_dir.kobj != targ)
                goto out;
 
-       result = sysfs_rename(sd, parent_sd, new);
+       if (sysfs_ns_type(parent_sd))
+               new_ns = targ->ktype->namespace(targ);
+
+       result = sysfs_rename(sd, parent_sd, new_ns, new);
 
 out:
        sysfs_put(sd);