diff options
Diffstat (limited to 'fs/sysfs/symlink.c')
| -rw-r--r-- | fs/sysfs/symlink.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index f71246bebfe4..a7ac78f8e67a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
| 28 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
| 29 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
| 30 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
| 31 | enum kobj_ns_type ns_type; | ||
| 31 | int error; | 32 | int error; |
| 32 | 33 | ||
| 33 | BUG_ON(!name); | 34 | BUG_ON(!name); |
| @@ -58,16 +59,29 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
| 58 | if (!sd) | 59 | if (!sd) |
| 59 | goto out_put; | 60 | goto out_put; |
| 60 | 61 | ||
| 61 | if (sysfs_ns_type(parent_sd)) | 62 | ns_type = sysfs_ns_type(parent_sd); |
| 63 | if (ns_type) | ||
| 62 | sd->s_ns = target->ktype->namespace(target); | 64 | sd->s_ns = target->ktype->namespace(target); |
| 63 | sd->s_symlink.target_sd = target_sd; | 65 | sd->s_symlink.target_sd = target_sd; |
| 64 | target_sd = NULL; /* reference is now owned by the symlink */ | 66 | target_sd = NULL; /* reference is now owned by the symlink */ |
| 65 | 67 | ||
| 66 | sysfs_addrm_start(&acxt, parent_sd); | 68 | sysfs_addrm_start(&acxt, parent_sd); |
| 67 | if (warn) | 69 | /* Symlinks must be between directories with the same ns_type */ |
| 68 | error = sysfs_add_one(&acxt, sd); | 70 | if (!ns_type || |
| 69 | else | 71 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { |
| 70 | error = __sysfs_add_one(&acxt, sd); | 72 | if (warn) |
| 73 | error = sysfs_add_one(&acxt, sd); | ||
| 74 | else | ||
| 75 | error = __sysfs_add_one(&acxt, sd); | ||
| 76 | } else { | ||
| 77 | error = -EINVAL; | ||
| 78 | WARN(1, KERN_WARNING | ||
| 79 | "sysfs: symlink across ns_types %s/%s -> %s/%s\n", | ||
| 80 | parent_sd->s_name, | ||
| 81 | sd->s_name, | ||
| 82 | sd->s_symlink.target_sd->s_parent->s_name, | ||
| 83 | sd->s_symlink.target_sd->s_name); | ||
| 84 | } | ||
| 71 | sysfs_addrm_finish(&acxt); | 85 | sysfs_addrm_finish(&acxt); |
| 72 | 86 | ||
| 73 | if (error) | 87 | if (error) |
| @@ -122,7 +136,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | |||
| 122 | { | 136 | { |
| 123 | const void *ns = NULL; | 137 | const void *ns = NULL; |
| 124 | spin_lock(&sysfs_assoc_lock); | 138 | spin_lock(&sysfs_assoc_lock); |
| 125 | if (targ->sd) | 139 | if (targ->sd && sysfs_ns_type(kobj->sd)) |
| 126 | ns = targ->sd->s_ns; | 140 | ns = targ->sd->s_ns; |
| 127 | spin_unlock(&sysfs_assoc_lock); | 141 | spin_unlock(&sysfs_assoc_lock); |
| 128 | sysfs_hash_and_remove(kobj->sd, ns, name); | 142 | sysfs_hash_and_remove(kobj->sd, ns, name); |
