1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* -*- mode: c; c-basic-offset: 8; -*-
3 * vim: noexpandtab sw=8 ts=8 sts=0:
5 * symlink.c - operations for configfs symlinks.
8 * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
10 * configfs Copyright (C) 2005 Oracle. All rights reserved.
14 #include <linux/module.h>
15 #include <linux/namei.h>
16 #include <linux/slab.h>
18 #include <linux/configfs.h>
19 #include "configfs_internal.h"
21 /* Protects attachments of new symlinks */
22 DEFINE_MUTEX(configfs_symlink_mutex
);
24 static int item_depth(struct config_item
* item
)
26 struct config_item
* p
= item
;
28 do { depth
++; } while ((p
= p
->ci_parent
) && !configfs_is_root(p
));
32 static int item_path_length(struct config_item
* item
)
34 struct config_item
* p
= item
;
37 length
+= strlen(config_item_name(p
)) + 1;
39 } while (p
&& !configfs_is_root(p
));
43 static void fill_item_path(struct config_item
* item
, char * buffer
, int length
)
45 struct config_item
* p
;
48 for (p
= item
; p
&& !configfs_is_root(p
); p
= p
->ci_parent
) {
49 int cur
= strlen(config_item_name(p
));
51 /* back up enough to print this bus id with '/' */
53 memcpy(buffer
+ length
, config_item_name(p
), cur
);
54 *(buffer
+ --length
) = '/';
58 static int configfs_get_target_path(struct config_item
*item
,
59 struct config_item
*target
, char *path
)
64 depth
= item_depth(item
);
65 size
= item_path_length(target
) + depth
* 3 - 1;
69 pr_debug("%s: depth = %d, size = %d\n", __func__
, depth
, size
);
71 for (s
= path
; depth
--; s
+= 3)
74 fill_item_path(target
, path
, size
);
75 pr_debug("%s: path = '%s'\n", __func__
, path
);
79 static int create_link(struct config_item
*parent_item
,
80 struct config_item
*item
,
81 struct dentry
*dentry
)
83 struct configfs_dirent
*target_sd
= item
->ci_dentry
->d_fsdata
;
87 if (!configfs_dirent_is_ready(target_sd
))
90 body
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
94 configfs_get(target_sd
);
95 spin_lock(&configfs_dirent_lock
);
96 if (target_sd
->s_type
& CONFIGFS_USET_DROPPING
) {
97 spin_unlock(&configfs_dirent_lock
);
98 configfs_put(target_sd
);
102 target_sd
->s_links
++;
103 spin_unlock(&configfs_dirent_lock
);
104 ret
= configfs_get_target_path(parent_item
, item
, body
);
106 ret
= configfs_create_link(target_sd
, parent_item
->ci_dentry
,
109 spin_lock(&configfs_dirent_lock
);
110 target_sd
->s_links
--;
111 spin_unlock(&configfs_dirent_lock
);
112 configfs_put(target_sd
);
119 static int get_target(const char *symname
, struct path
*path
,
120 struct config_item
**target
, struct super_block
*sb
)
124 ret
= kern_path(symname
, LOOKUP_FOLLOW
|LOOKUP_DIRECTORY
, path
);
126 if (path
->dentry
->d_sb
== sb
) {
127 *target
= configfs_get_config_item(path
->dentry
);
142 int configfs_symlink(struct inode
*dir
, struct dentry
*dentry
, const char *symname
)
146 struct configfs_dirent
*sd
;
147 struct config_item
*parent_item
;
148 struct config_item
*target_item
= NULL
;
149 const struct config_item_type
*type
;
151 sd
= dentry
->d_parent
->d_fsdata
;
153 * Fake invisibility if dir belongs to a group/default groups hierarchy
156 if (!configfs_dirent_is_ready(sd
))
159 parent_item
= configfs_get_config_item(dentry
->d_parent
);
160 type
= parent_item
->ci_type
;
163 if (!type
|| !type
->ct_item_ops
||
164 !type
->ct_item_ops
->allow_link
)
168 * This is really sick. What they wanted was a hybrid of
169 * link(2) and symlink(2) - they wanted the target resolved
170 * at syscall time (as link(2) would've done), be a directory
171 * (which link(2) would've refused to do) *AND* be a deep
172 * fucking magic, making the target busy from rmdir POV.
173 * symlink(2) is nothing of that sort, and the locking it
174 * gets matches the normal symlink(2) semantics. Without
175 * attempts to resolve the target (which might very well
176 * not even exist yet) done prior to locking the parent
177 * directory. This perversion, OTOH, needs to resolve
178 * the target, which would lead to obvious deadlocks if
179 * attempted with any directories locked.
181 * Unfortunately, that garbage is userland ABI and we should've
182 * said "no" back in 2005. Too late now, so we get to
183 * play very ugly games with locking.
185 * Try *ANYTHING* of that sort in new code, and you will
186 * really regret it. Just ask yourself - what could a BOFH
187 * do to me and do I want to find it out first-hand?
189 * AV, a thoroughly annoyed bastard.
192 ret
= get_target(symname
, &path
, &target_item
, dentry
->d_sb
);
197 if (dentry
->d_inode
|| d_unhashed(dentry
))
200 ret
= inode_permission(dir
, MAY_WRITE
| MAY_EXEC
);
202 ret
= type
->ct_item_ops
->allow_link(parent_item
, target_item
);
204 mutex_lock(&configfs_symlink_mutex
);
205 ret
= create_link(parent_item
, target_item
, dentry
);
206 mutex_unlock(&configfs_symlink_mutex
);
207 if (ret
&& type
->ct_item_ops
->drop_link
)
208 type
->ct_item_ops
->drop_link(parent_item
,
212 config_item_put(target_item
);
216 config_item_put(parent_item
);
220 int configfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
222 struct configfs_dirent
*sd
= dentry
->d_fsdata
, *target_sd
;
223 struct config_item
*parent_item
;
224 const struct config_item_type
*type
;
227 ret
= -EPERM
; /* What lack-of-symlink returns */
228 if (!(sd
->s_type
& CONFIGFS_ITEM_LINK
))
231 target_sd
= sd
->s_element
;
233 parent_item
= configfs_get_config_item(dentry
->d_parent
);
234 type
= parent_item
->ci_type
;
236 spin_lock(&configfs_dirent_lock
);
237 list_del_init(&sd
->s_sibling
);
238 spin_unlock(&configfs_dirent_lock
);
239 configfs_drop_dentry(sd
, dentry
->d_parent
);
244 * drop_link() must be called before
245 * decrementing target's ->s_links, so that the order of
246 * drop_link(this, target) and drop_item(target) is preserved.
248 if (type
&& type
->ct_item_ops
&&
249 type
->ct_item_ops
->drop_link
)
250 type
->ct_item_ops
->drop_link(parent_item
,
251 target_sd
->s_element
);
253 spin_lock(&configfs_dirent_lock
);
254 target_sd
->s_links
--;
255 spin_unlock(&configfs_dirent_lock
);
256 configfs_put(target_sd
);
258 config_item_put(parent_item
);
266 const struct inode_operations configfs_symlink_inode_operations
= {
267 .get_link
= simple_get_link
,
268 .setattr
= configfs_setattr
,