diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 05373db21a4e..d4d871fba21e 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -78,6 +78,92 @@ static const struct dentry_operations configfs_dentry_ops = { | |||
78 | .d_delete = configfs_d_delete, | 78 | .d_delete = configfs_d_delete, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | #ifdef CONFIG_LOCKDEP | ||
82 | |||
83 | /* | ||
84 | * Helpers to make lockdep happy with our recursive locking of default groups' | ||
85 | * inodes (see configfs_attach_group() and configfs_detach_group()). | ||
86 | * We put default groups i_mutexes in separate classes according to their depth | ||
87 | * from the youngest non-default group ancestor. | ||
88 | * | ||
89 | * For a non-default group A having default groups A/B, A/C, and A/C/D, default | ||
90 | * groups A/B and A/C will have their inode's mutex in class | ||
91 | * default_group_class[0], and default group A/C/D will be in | ||
92 | * default_group_class[1]. | ||
93 | * | ||
94 | * The lock classes are declared and assigned in inode.c, according to the | ||
95 | * s_depth value. | ||
96 | * The s_depth value is initialized to -1, adjusted to >= 0 when attaching | ||
97 | * default groups, and reset to -1 when all default groups are attached. During | ||
98 | * attachment, if configfs_create() sees s_depth > 0, the lock class of the new | ||
99 | * inode's mutex is set to default_group_class[s_depth - 1]. | ||
100 | */ | ||
101 | |||
102 | static void configfs_init_dirent_depth(struct configfs_dirent *sd) | ||
103 | { | ||
104 | sd->s_depth = -1; | ||
105 | } | ||
106 | |||
107 | static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd, | ||
108 | struct configfs_dirent *sd) | ||
109 | { | ||
110 | int parent_depth = parent_sd->s_depth; | ||
111 | |||
112 | if (parent_depth >= 0) | ||
113 | sd->s_depth = parent_depth + 1; | ||
114 | } | ||
115 | |||
116 | static void | ||
117 | configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd) | ||
118 | { | ||
119 | /* | ||
120 | * item's i_mutex class is already setup, so s_depth is now only | ||
121 | * used to set new sub-directories s_depth, which is always done | ||
122 | * with item's i_mutex locked. | ||
123 | */ | ||
124 | /* | ||
125 | * sd->s_depth == -1 iff we are a non default group. | ||
126 | * else (we are a default group) sd->s_depth > 0 (see | ||
127 | * create_dir()). | ||
128 | */ | ||
129 | if (sd->s_depth == -1) | ||
130 | /* | ||
131 | * We are a non default group and we are going to create | ||
132 | * default groups. | ||
133 | */ | ||
134 | sd->s_depth = 0; | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd) | ||
139 | { | ||
140 | /* We will not create default groups anymore. */ | ||
141 | sd->s_depth = -1; | ||
142 | } | ||
143 | |||
144 | #else /* CONFIG_LOCKDEP */ | ||
145 | |||
146 | static void configfs_init_dirent_depth(struct configfs_dirent *sd) | ||
147 | { | ||
148 | } | ||
149 | |||
150 | static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd, | ||
151 | struct configfs_dirent *sd) | ||
152 | { | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd) | ||
157 | { | ||
158 | } | ||
159 | |||
160 | static void | ||
161 | configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd) | ||
162 | { | ||
163 | } | ||
164 | |||
165 | #endif /* CONFIG_LOCKDEP */ | ||
166 | |||
81 | /* | 167 | /* |
82 | * Allocates a new configfs_dirent and links it to the parent configfs_dirent | 168 | * Allocates a new configfs_dirent and links it to the parent configfs_dirent |
83 | */ | 169 | */ |
@@ -94,6 +180,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare | |||
94 | INIT_LIST_HEAD(&sd->s_links); | 180 | INIT_LIST_HEAD(&sd->s_links); |
95 | INIT_LIST_HEAD(&sd->s_children); | 181 | INIT_LIST_HEAD(&sd->s_children); |
96 | sd->s_element = element; | 182 | sd->s_element = element; |
183 | configfs_init_dirent_depth(sd); | ||
97 | spin_lock(&configfs_dirent_lock); | 184 | spin_lock(&configfs_dirent_lock); |
98 | if (parent_sd->s_type & CONFIGFS_USET_DROPPING) { | 185 | if (parent_sd->s_type & CONFIGFS_USET_DROPPING) { |
99 | spin_unlock(&configfs_dirent_lock); | 186 | spin_unlock(&configfs_dirent_lock); |
@@ -187,6 +274,7 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
187 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, | 274 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, |
188 | CONFIGFS_DIR | CONFIGFS_USET_CREATING); | 275 | CONFIGFS_DIR | CONFIGFS_USET_CREATING); |
189 | if (!error) { | 276 | if (!error) { |
277 | configfs_set_dir_dirent_depth(p->d_fsdata, d->d_fsdata); | ||
190 | error = configfs_create(d, mode, init_dir); | 278 | error = configfs_create(d, mode, init_dir); |
191 | if (!error) { | 279 | if (!error) { |
192 | inc_nlink(p->d_inode); | 280 | inc_nlink(p->d_inode); |
@@ -789,11 +877,13 @@ static int configfs_attach_group(struct config_item *parent_item, | |||
789 | * error, as rmdir() would. | 877 | * error, as rmdir() would. |
790 | */ | 878 | */ |
791 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | 879 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); |
880 | configfs_adjust_dir_dirent_depth_before_populate(sd); | ||
792 | ret = populate_groups(to_config_group(item)); | 881 | ret = populate_groups(to_config_group(item)); |
793 | if (ret) { | 882 | if (ret) { |
794 | configfs_detach_item(item); | 883 | configfs_detach_item(item); |
795 | dentry->d_inode->i_flags |= S_DEAD; | 884 | dentry->d_inode->i_flags |= S_DEAD; |
796 | } | 885 | } |
886 | configfs_adjust_dir_dirent_depth_after_populate(sd); | ||
797 | mutex_unlock(&dentry->d_inode->i_mutex); | 887 | mutex_unlock(&dentry->d_inode->i_mutex); |
798 | if (ret) | 888 | if (ret) |
799 | d_delete(dentry); | 889 | d_delete(dentry); |