aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs/dir.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-28 14:54:40 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 21:10:48 -0500
commitba7443bc656e5236c316b2acacc8b551f872910f (patch)
tree08b9a7a0504ae77abc634419167958ce4e6c4e64 /fs/kernfs/dir.c
parent061447a496b915f1dc8f8c645c6825f856d2bbac (diff)
sysfs, kernfs: implement kernfs_create/destroy_root()
There currently is single kernfs hierarchy in the whole system which is used for sysfs. kernfs needs to support multiple hierarchies to allow other users. This patch introduces struct kernfs_root which serves as the root of each kernfs hierarchy and implements kernfs_create/destroy_root(). * Each kernfs_root is associated with a root sd (sysfs_dentry). The root is freed when the root sd is released and kernfs_destory_root() simply invokes kernfs_remove() on the root sd. sysfs_remove_one() is updated to handle release of the root sd. Note that ps_iattr update in sysfs_remove_one() is trivially updated for readability. * Root sd's are now dynamically allocated using sysfs_new_dirent(). Update sysfs_alloc_ino() so that it gives out ino from 1 so that the root sd still gets ino 1. * While kernfs currently only points to the root sd, it'll soon grow fields which are specific to each hierarchy. As determining a given sd's root will be necessary, sd->s_dir.root is added. This backlink fits better as a separate field in sd; however, sd->s_dir is inside union with space to spare, so use it to save space and provide kernfs_root() accessor to determine the root sd. * As hierarchies may be destroyed now, each mount needs to hold onto the hierarchy it's attached to. Update sysfs_fill_super() and sysfs_kill_sb() so that they get and put the kernfs_root respectively. * sysfs_root is replaced with kernfs_root which is dynamically created by invoking kernfs_create_root() from sysfs_init(). This patch doesn't introduce any visible behavior changes. v2: kernfs_create_root() forgot to set @sd->priv. Fixed. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs/dir.c')
-rw-r--r--fs/kernfs/dir.c71
1 files changed, 62 insertions, 9 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index a4ca4de3cb21..246740a741ef 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -211,7 +211,7 @@ static int sysfs_alloc_ino(unsigned int *pino)
211 211
212 retry: 212 retry:
213 spin_lock(&sysfs_ino_lock); 213 spin_lock(&sysfs_ino_lock);
214 rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino); 214 rc = ida_get_new_above(&sysfs_ino_ida, 1, &ino);
215 spin_unlock(&sysfs_ino_lock); 215 spin_unlock(&sysfs_ino_lock);
216 216
217 if (rc == -EAGAIN) { 217 if (rc == -EAGAIN) {
@@ -253,9 +253,11 @@ EXPORT_SYMBOL_GPL(kernfs_get);
253void kernfs_put(struct sysfs_dirent *sd) 253void kernfs_put(struct sysfs_dirent *sd)
254{ 254{
255 struct sysfs_dirent *parent_sd; 255 struct sysfs_dirent *parent_sd;
256 struct kernfs_root *root;
256 257
257 if (!sd || !atomic_dec_and_test(&sd->s_count)) 258 if (!sd || !atomic_dec_and_test(&sd->s_count))
258 return; 259 return;
260 root = kernfs_root(sd);
259 repeat: 261 repeat:
260 /* Moving/renaming is always done while holding reference. 262 /* Moving/renaming is always done while holding reference.
261 * sd->s_parent won't change beneath us. 263 * sd->s_parent won't change beneath us.
@@ -278,8 +280,13 @@ void kernfs_put(struct sysfs_dirent *sd)
278 kmem_cache_free(sysfs_dir_cachep, sd); 280 kmem_cache_free(sysfs_dir_cachep, sd);
279 281
280 sd = parent_sd; 282 sd = parent_sd;
281 if (sd && atomic_dec_and_test(&sd->s_count)) 283 if (sd) {
282 goto repeat; 284 if (atomic_dec_and_test(&sd->s_count))
285 goto repeat;
286 } else {
287 /* just released the root sd, free @root too */
288 kfree(root);
289 }
283} 290}
284EXPORT_SYMBOL_GPL(kernfs_put); 291EXPORT_SYMBOL_GPL(kernfs_put);
285 292
@@ -493,13 +500,15 @@ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
493 if (sd->s_flags & SYSFS_FLAG_REMOVED) 500 if (sd->s_flags & SYSFS_FLAG_REMOVED)
494 return; 501 return;
495 502
496 sysfs_unlink_sibling(sd); 503 if (sd->s_parent) {
504 sysfs_unlink_sibling(sd);
497 505
498 /* Update timestamps on the parent */ 506 /* Update timestamps on the parent */
499 ps_iattr = sd->s_parent->s_iattr; 507 ps_iattr = sd->s_parent->s_iattr;
500 if (ps_iattr) { 508 if (ps_iattr) {
501 struct iattr *ps_iattrs = &ps_iattr->ia_iattr; 509 ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
502 ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; 510 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
511 }
503 } 512 }
504 513
505 sd->s_flags |= SYSFS_FLAG_REMOVED; 514 sd->s_flags |= SYSFS_FLAG_REMOVED;
@@ -604,6 +613,49 @@ struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent,
604EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 613EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
605 614
606/** 615/**
616 * kernfs_create_root - create a new kernfs hierarchy
617 * @priv: opaque data associated with the new directory
618 *
619 * Returns the root of the new hierarchy on success, ERR_PTR() value on
620 * failure.
621 */
622struct kernfs_root *kernfs_create_root(void *priv)
623{
624 struct kernfs_root *root;
625 struct sysfs_dirent *sd;
626
627 root = kzalloc(sizeof(*root), GFP_KERNEL);
628 if (!root)
629 return ERR_PTR(-ENOMEM);
630
631 sd = sysfs_new_dirent("", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR);
632 if (!sd) {
633 kfree(root);
634 return ERR_PTR(-ENOMEM);
635 }
636
637 sd->s_flags &= ~SYSFS_FLAG_REMOVED;
638 sd->priv = priv;
639 sd->s_dir.root = root;
640
641 root->sd = sd;
642
643 return root;
644}
645
646/**
647 * kernfs_destroy_root - destroy a kernfs hierarchy
648 * @root: root of the hierarchy to destroy
649 *
650 * Destroy the hierarchy anchored at @root by removing all existing
651 * directories and destroying @root.
652 */
653void kernfs_destroy_root(struct kernfs_root *root)
654{
655 kernfs_remove(root->sd); /* will also free @root */
656}
657
658/**
607 * kernfs_create_dir_ns - create a directory 659 * kernfs_create_dir_ns - create a directory
608 * @parent: parent in which to create a new directory 660 * @parent: parent in which to create a new directory
609 * @name: name of the new directory 661 * @name: name of the new directory
@@ -626,6 +678,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent,
626 if (!sd) 678 if (!sd)
627 return ERR_PTR(-ENOMEM); 679 return ERR_PTR(-ENOMEM);
628 680
681 sd->s_dir.root = parent->s_dir.root;
629 sd->s_ns = ns; 682 sd->s_ns = ns;
630 sd->priv = priv; 683 sd->priv = priv;
631 684