diff options
| -rw-r--r-- | fs/configfs/configfs_internal.h | 3 | ||||
| -rw-r--r-- | fs/configfs/dir.c | 90 | ||||
| -rw-r--r-- | fs/configfs/inode.c | 38 |
3 files changed, 131 insertions, 0 deletions
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 762d287123ca..da6061a6df40 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
| @@ -39,6 +39,9 @@ struct configfs_dirent { | |||
| 39 | umode_t s_mode; | 39 | umode_t s_mode; |
| 40 | struct dentry * s_dentry; | 40 | struct dentry * s_dentry; |
| 41 | struct iattr * s_iattr; | 41 | struct iattr * s_iattr; |
| 42 | #ifdef CONFIG_LOCKDEP | ||
| 43 | int s_depth; | ||
| 44 | #endif | ||
| 42 | }; | 45 | }; |
| 43 | 46 | ||
| 44 | #define CONFIGFS_ROOT 0x0001 | 47 | #define CONFIGFS_ROOT 0x0001 |
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); |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 5d349d38e056..4921e7426d95 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
| @@ -33,10 +33,15 @@ | |||
| 33 | #include <linux/backing-dev.h> | 33 | #include <linux/backing-dev.h> |
| 34 | #include <linux/capability.h> | 34 | #include <linux/capability.h> |
| 35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
| 36 | #include <linux/lockdep.h> | ||
| 36 | 37 | ||
| 37 | #include <linux/configfs.h> | 38 | #include <linux/configfs.h> |
| 38 | #include "configfs_internal.h" | 39 | #include "configfs_internal.h" |
| 39 | 40 | ||
| 41 | #ifdef CONFIG_LOCKDEP | ||
| 42 | static struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; | ||
| 43 | #endif | ||
| 44 | |||
| 40 | extern struct super_block * configfs_sb; | 45 | extern struct super_block * configfs_sb; |
| 41 | 46 | ||
| 42 | static const struct address_space_operations configfs_aops = { | 47 | static const struct address_space_operations configfs_aops = { |
| @@ -150,6 +155,38 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) | |||
| 150 | return inode; | 155 | return inode; |
| 151 | } | 156 | } |
| 152 | 157 | ||
| 158 | #ifdef CONFIG_LOCKDEP | ||
| 159 | |||
| 160 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, | ||
| 161 | struct inode *inode) | ||
| 162 | { | ||
| 163 | int depth = sd->s_depth; | ||
| 164 | |||
| 165 | if (depth > 0) { | ||
| 166 | if (depth <= ARRAY_SIZE(default_group_class)) { | ||
| 167 | lockdep_set_class(&inode->i_mutex, | ||
| 168 | &default_group_class[depth - 1]); | ||
| 169 | } else { | ||
| 170 | /* | ||
| 171 | * In practice the maximum level of locking depth is | ||
| 172 | * already reached. Just inform about possible reasons. | ||
| 173 | */ | ||
| 174 | printk(KERN_INFO "configfs: Too many levels of inodes" | ||
| 175 | " for the locking correctness validator.\n"); | ||
| 176 | printk(KERN_INFO "Spurious warnings may appear.\n"); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | #else /* CONFIG_LOCKDEP */ | ||
| 182 | |||
| 183 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, | ||
| 184 | struct inode *inode) | ||
| 185 | { | ||
| 186 | } | ||
| 187 | |||
| 188 | #endif /* CONFIG_LOCKDEP */ | ||
| 189 | |||
| 153 | int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | 190 | int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) |
| 154 | { | 191 | { |
| 155 | int error = 0; | 192 | int error = 0; |
| @@ -162,6 +199,7 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode * | |||
| 162 | struct inode *p_inode = dentry->d_parent->d_inode; | 199 | struct inode *p_inode = dentry->d_parent->d_inode; |
| 163 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | 200 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; |
| 164 | } | 201 | } |
| 202 | configfs_set_inode_lock_class(sd, inode); | ||
| 165 | goto Proceed; | 203 | goto Proceed; |
| 166 | } | 204 | } |
| 167 | else | 205 | else |
