diff options
Diffstat (limited to 'fs/sdcardfs/packagelist.c')
-rw-r--r-- | fs/sdcardfs/packagelist.c | 859 |
1 files changed, 654 insertions, 205 deletions
diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 9c3340528eee..89196e31073e 100644 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c | |||
@@ -20,8 +20,10 @@ | |||
20 | 20 | ||
21 | #include "sdcardfs.h" | 21 | #include "sdcardfs.h" |
22 | #include <linux/hashtable.h> | 22 | #include <linux/hashtable.h> |
23 | #include <linux/ctype.h> | ||
23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
24 | 25 | #include <linux/radix-tree.h> | |
26 | #include <linux/dcache.h> | ||
25 | 27 | ||
26 | #include <linux/init.h> | 28 | #include <linux/init.h> |
27 | #include <linux/module.h> | 29 | #include <linux/module.h> |
@@ -29,386 +31,835 @@ | |||
29 | 31 | ||
30 | #include <linux/configfs.h> | 32 | #include <linux/configfs.h> |
31 | 33 | ||
32 | #define STRING_BUF_SIZE (512) | ||
33 | |||
34 | struct hashtable_entry { | 34 | struct hashtable_entry { |
35 | struct hlist_node hlist; | 35 | struct hlist_node hlist; |
36 | void *key; | 36 | struct hlist_node dlist; /* for deletion cleanup */ |
37 | unsigned int value; | 37 | struct qstr key; |
38 | atomic_t value; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | struct sb_list { | 41 | static DEFINE_HASHTABLE(package_to_appid, 8); |
41 | struct super_block *sb; | 42 | static DEFINE_HASHTABLE(package_to_userid, 8); |
42 | struct list_head list; | 43 | static DEFINE_HASHTABLE(ext_to_groupid, 8); |
43 | }; | ||
44 | 44 | ||
45 | struct packagelist_data { | ||
46 | DECLARE_HASHTABLE(package_to_appid,8); | ||
47 | struct mutex hashtable_lock; | ||
48 | 45 | ||
49 | }; | 46 | static struct kmem_cache *hashtable_entry_cachep; |
50 | 47 | ||
51 | static struct packagelist_data *pkgl_data_all; | 48 | static unsigned int full_name_case_hash(const unsigned char *name, unsigned int len) |
49 | { | ||
50 | unsigned long hash = init_name_hash(); | ||
52 | 51 | ||
53 | static struct kmem_cache *hashtable_entry_cachep; | 52 | while (len--) |
53 | hash = partial_name_hash(tolower(*name++), hash); | ||
54 | return end_name_hash(hash); | ||
55 | } | ||
54 | 56 | ||
55 | static unsigned int str_hash(const char *key) { | 57 | static inline void qstr_init(struct qstr *q, const char *name) |
56 | int i; | 58 | { |
57 | unsigned int h = strlen(key); | 59 | q->name = name; |
58 | char *data = (char *)key; | 60 | q->len = strlen(q->name); |
61 | q->hash = full_name_case_hash(q->name, q->len); | ||
62 | } | ||
63 | |||
64 | static inline int qstr_copy(const struct qstr *src, struct qstr *dest) | ||
65 | { | ||
66 | dest->name = kstrdup(src->name, GFP_KERNEL); | ||
67 | dest->hash_len = src->hash_len; | ||
68 | return !!dest->name; | ||
69 | } | ||
70 | |||
71 | |||
72 | static appid_t __get_appid(const struct qstr *key) | ||
73 | { | ||
74 | struct hashtable_entry *hash_cur; | ||
75 | unsigned int hash = key->hash; | ||
76 | appid_t ret_id; | ||
59 | 77 | ||
60 | for (i = 0; i < strlen(key); i++) { | 78 | rcu_read_lock(); |
61 | h = h * 31 + *data; | 79 | hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { |
62 | data++; | 80 | if (qstr_case_eq(key, &hash_cur->key)) { |
81 | ret_id = atomic_read(&hash_cur->value); | ||
82 | rcu_read_unlock(); | ||
83 | return ret_id; | ||
84 | } | ||
63 | } | 85 | } |
64 | return h; | 86 | rcu_read_unlock(); |
87 | return 0; | ||
88 | } | ||
89 | |||
90 | appid_t get_appid(const char *key) | ||
91 | { | ||
92 | struct qstr q; | ||
93 | |||
94 | qstr_init(&q, key); | ||
95 | return __get_appid(&q); | ||
65 | } | 96 | } |
66 | 97 | ||
67 | appid_t get_appid(void *pkgl_id, const char *app_name) | 98 | static appid_t __get_ext_gid(const struct qstr *key) |
68 | { | 99 | { |
69 | struct packagelist_data *pkgl_dat = pkgl_data_all; | ||
70 | struct hashtable_entry *hash_cur; | 100 | struct hashtable_entry *hash_cur; |
71 | unsigned int hash = str_hash(app_name); | 101 | unsigned int hash = key->hash; |
72 | appid_t ret_id; | 102 | appid_t ret_id; |
73 | 103 | ||
74 | mutex_lock(&pkgl_dat->hashtable_lock); | 104 | rcu_read_lock(); |
75 | hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { | 105 | hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { |
76 | if (!strcasecmp(app_name, hash_cur->key)) { | 106 | if (qstr_case_eq(key, &hash_cur->key)) { |
77 | ret_id = (appid_t)hash_cur->value; | 107 | ret_id = atomic_read(&hash_cur->value); |
78 | mutex_unlock(&pkgl_dat->hashtable_lock); | 108 | rcu_read_unlock(); |
79 | return ret_id; | 109 | return ret_id; |
80 | } | 110 | } |
81 | } | 111 | } |
82 | mutex_unlock(&pkgl_dat->hashtable_lock); | 112 | rcu_read_unlock(); |
113 | return 0; | ||
114 | } | ||
115 | |||
116 | appid_t get_ext_gid(const char *key) | ||
117 | { | ||
118 | struct qstr q; | ||
119 | |||
120 | qstr_init(&q, key); | ||
121 | return __get_ext_gid(&q); | ||
122 | } | ||
123 | |||
124 | static appid_t __is_excluded(const struct qstr *app_name, userid_t user) | ||
125 | { | ||
126 | struct hashtable_entry *hash_cur; | ||
127 | unsigned int hash = app_name->hash; | ||
128 | |||
129 | rcu_read_lock(); | ||
130 | hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { | ||
131 | if (atomic_read(&hash_cur->value) == user && | ||
132 | qstr_case_eq(app_name, &hash_cur->key)) { | ||
133 | rcu_read_unlock(); | ||
134 | return 1; | ||
135 | } | ||
136 | } | ||
137 | rcu_read_unlock(); | ||
83 | return 0; | 138 | return 0; |
84 | } | 139 | } |
85 | 140 | ||
141 | appid_t is_excluded(const char *key, userid_t user) | ||
142 | { | ||
143 | struct qstr q; | ||
144 | qstr_init(&q, key); | ||
145 | return __is_excluded(&q, user); | ||
146 | } | ||
147 | |||
86 | /* Kernel has already enforced everything we returned through | 148 | /* Kernel has already enforced everything we returned through |
87 | * derive_permissions_locked(), so this is used to lock down access | 149 | * derive_permissions_locked(), so this is used to lock down access |
88 | * even further, such as enforcing that apps hold sdcard_rw. */ | 150 | * even further, such as enforcing that apps hold sdcard_rw. |
89 | int check_caller_access_to_name(struct inode *parent_node, const char* name) { | 151 | */ |
152 | int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name) | ||
153 | { | ||
154 | struct qstr q_autorun = QSTR_LITERAL("autorun.inf"); | ||
155 | struct qstr q__android_secure = QSTR_LITERAL(".android_secure"); | ||
156 | struct qstr q_android_secure = QSTR_LITERAL("android_secure"); | ||
90 | 157 | ||
91 | /* Always block security-sensitive files at root */ | 158 | /* Always block security-sensitive files at root */ |
92 | if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { | 159 | if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { |
93 | if (!strcasecmp(name, "autorun.inf") | 160 | if (qstr_case_eq(name, &q_autorun) |
94 | || !strcasecmp(name, ".android_secure") | 161 | || qstr_case_eq(name, &q__android_secure) |
95 | || !strcasecmp(name, "android_secure")) { | 162 | || qstr_case_eq(name, &q_android_secure)) { |
96 | return 0; | 163 | return 0; |
97 | } | 164 | } |
98 | } | 165 | } |
99 | 166 | ||
100 | /* Root always has access; access for any other UIDs should always | 167 | /* Root always has access; access for any other UIDs should always |
101 | * be controlled through packages.list. */ | 168 | * be controlled through packages.list. |
102 | if (from_kuid(&init_user_ns, current_fsuid()) == 0) { | 169 | */ |
170 | if (from_kuid(&init_user_ns, current_fsuid()) == 0) | ||
103 | return 1; | 171 | return 1; |
104 | } | ||
105 | 172 | ||
106 | /* No extra permissions to enforce */ | 173 | /* No extra permissions to enforce */ |
107 | return 1; | 174 | return 1; |
108 | } | 175 | } |
109 | 176 | ||
110 | /* This function is used when file opening. The open flags must be | 177 | /* This function is used when file opening. The open flags must be |
111 | * checked before calling check_caller_access_to_name() */ | 178 | * checked before calling check_caller_access_to_name() |
112 | int open_flags_to_access_mode(int open_flags) { | 179 | */ |
113 | if((open_flags & O_ACCMODE) == O_RDONLY) { | 180 | int open_flags_to_access_mode(int open_flags) |
181 | { | ||
182 | if ((open_flags & O_ACCMODE) == O_RDONLY) | ||
114 | return 0; /* R_OK */ | 183 | return 0; /* R_OK */ |
115 | } else if ((open_flags & O_ACCMODE) == O_WRONLY) { | 184 | if ((open_flags & O_ACCMODE) == O_WRONLY) |
116 | return 1; /* W_OK */ | 185 | return 1; /* W_OK */ |
117 | } else { | 186 | /* Probably O_RDRW, but treat as default to be safe */ |
118 | /* Probably O_RDRW, but treat as default to be safe */ | ||
119 | return 1; /* R_OK | W_OK */ | 187 | return 1; /* R_OK | W_OK */ |
188 | } | ||
189 | |||
190 | static struct hashtable_entry *alloc_hashtable_entry(const struct qstr *key, | ||
191 | appid_t value) | ||
192 | { | ||
193 | struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, | ||
194 | GFP_KERNEL); | ||
195 | if (!ret) | ||
196 | return NULL; | ||
197 | INIT_HLIST_NODE(&ret->dlist); | ||
198 | INIT_HLIST_NODE(&ret->hlist); | ||
199 | |||
200 | if (!qstr_copy(key, &ret->key)) { | ||
201 | kmem_cache_free(hashtable_entry_cachep, ret); | ||
202 | return NULL; | ||
120 | } | 203 | } |
204 | |||
205 | atomic_set(&ret->value, value); | ||
206 | return ret; | ||
121 | } | 207 | } |
122 | 208 | ||
123 | static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, | 209 | static int insert_packagelist_appid_entry_locked(const struct qstr *key, appid_t value) |
124 | unsigned int value) | ||
125 | { | 210 | { |
126 | struct hashtable_entry *hash_cur; | 211 | struct hashtable_entry *hash_cur; |
127 | struct hashtable_entry *new_entry; | 212 | struct hashtable_entry *new_entry; |
128 | unsigned int hash = str_hash(key); | 213 | unsigned int hash = key->hash; |
129 | 214 | ||
130 | hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { | 215 | hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { |
131 | if (!strcasecmp(key, hash_cur->key)) { | 216 | if (qstr_case_eq(key, &hash_cur->key)) { |
132 | hash_cur->value = value; | 217 | atomic_set(&hash_cur->value, value); |
133 | return 0; | 218 | return 0; |
134 | } | 219 | } |
135 | } | 220 | } |
136 | new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); | 221 | new_entry = alloc_hashtable_entry(key, value); |
137 | if (!new_entry) | 222 | if (!new_entry) |
138 | return -ENOMEM; | 223 | return -ENOMEM; |
139 | new_entry->key = kstrdup(key, GFP_KERNEL); | 224 | hash_add_rcu(package_to_appid, &new_entry->hlist, hash); |
140 | new_entry->value = value; | ||
141 | hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); | ||
142 | return 0; | 225 | return 0; |
143 | } | 226 | } |
144 | 227 | ||
145 | static void fixup_perms(struct super_block *sb) { | 228 | static int insert_ext_gid_entry_locked(const struct qstr *key, appid_t value) |
146 | if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { | 229 | { |
147 | mutex_lock(&sb->s_root->d_inode->i_mutex); | 230 | struct hashtable_entry *hash_cur; |
148 | get_derive_permissions_recursive(sb->s_root); | 231 | struct hashtable_entry *new_entry; |
149 | mutex_unlock(&sb->s_root->d_inode->i_mutex); | 232 | unsigned int hash = key->hash; |
233 | |||
234 | /* An extension can only belong to one gid */ | ||
235 | hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { | ||
236 | if (qstr_case_eq(key, &hash_cur->key)) | ||
237 | return -EINVAL; | ||
150 | } | 238 | } |
239 | new_entry = alloc_hashtable_entry(key, value); | ||
240 | if (!new_entry) | ||
241 | return -ENOMEM; | ||
242 | hash_add_rcu(ext_to_groupid, &new_entry->hlist, hash); | ||
243 | return 0; | ||
151 | } | 244 | } |
152 | 245 | ||
153 | static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, | 246 | static int insert_userid_exclude_entry_locked(const struct qstr *key, userid_t value) |
154 | unsigned int value) { | 247 | { |
155 | int ret; | 248 | struct hashtable_entry *hash_cur; |
249 | struct hashtable_entry *new_entry; | ||
250 | unsigned int hash = key->hash; | ||
251 | |||
252 | /* Only insert if not already present */ | ||
253 | hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { | ||
254 | if (atomic_read(&hash_cur->value) == value && | ||
255 | qstr_case_eq(key, &hash_cur->key)) | ||
256 | return 0; | ||
257 | } | ||
258 | new_entry = alloc_hashtable_entry(key, value); | ||
259 | if (!new_entry) | ||
260 | return -ENOMEM; | ||
261 | hash_add_rcu(package_to_userid, &new_entry->hlist, hash); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static void fixup_all_perms_name(const struct qstr *key) | ||
266 | { | ||
156 | struct sdcardfs_sb_info *sbinfo; | 267 | struct sdcardfs_sb_info *sbinfo; |
157 | mutex_lock(&sdcardfs_super_list_lock); | 268 | struct limit_search limit = { |
158 | mutex_lock(&pkgl_dat->hashtable_lock); | 269 | .flags = BY_NAME, |
159 | ret = insert_str_to_int_lock(pkgl_dat, key, value); | 270 | .name = QSTR_INIT(key->name, key->len), |
160 | mutex_unlock(&pkgl_dat->hashtable_lock); | 271 | }; |
272 | list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { | ||
273 | if (sbinfo_has_sdcard_magic(sbinfo)) | ||
274 | fixup_perms_recursive(sbinfo->sb->s_root, &limit); | ||
275 | } | ||
276 | } | ||
161 | 277 | ||
278 | static void fixup_all_perms_name_userid(const struct qstr *key, userid_t userid) | ||
279 | { | ||
280 | struct sdcardfs_sb_info *sbinfo; | ||
281 | struct limit_search limit = { | ||
282 | .flags = BY_NAME | BY_USERID, | ||
283 | .name = QSTR_INIT(key->name, key->len), | ||
284 | .userid = userid, | ||
285 | }; | ||
162 | list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { | 286 | list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { |
163 | if (sbinfo) { | 287 | if (sbinfo_has_sdcard_magic(sbinfo)) |
164 | fixup_perms(sbinfo->sb); | 288 | fixup_perms_recursive(sbinfo->sb->s_root, &limit); |
165 | } | ||
166 | } | 289 | } |
290 | } | ||
291 | |||
292 | static void fixup_all_perms_userid(userid_t userid) | ||
293 | { | ||
294 | struct sdcardfs_sb_info *sbinfo; | ||
295 | struct limit_search limit = { | ||
296 | .flags = BY_USERID, | ||
297 | .userid = userid, | ||
298 | }; | ||
299 | list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { | ||
300 | if (sbinfo_has_sdcard_magic(sbinfo)) | ||
301 | fixup_perms_recursive(sbinfo->sb->s_root, &limit); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | static int insert_packagelist_entry(const struct qstr *key, appid_t value) | ||
306 | { | ||
307 | int err; | ||
308 | |||
309 | mutex_lock(&sdcardfs_super_list_lock); | ||
310 | err = insert_packagelist_appid_entry_locked(key, value); | ||
311 | if (!err) | ||
312 | fixup_all_perms_name(key); | ||
167 | mutex_unlock(&sdcardfs_super_list_lock); | 313 | mutex_unlock(&sdcardfs_super_list_lock); |
168 | return ret; | 314 | |
315 | return err; | ||
169 | } | 316 | } |
170 | 317 | ||
171 | static void remove_str_to_int_lock(struct hashtable_entry *h_entry) { | 318 | static int insert_ext_gid_entry(const struct qstr *key, appid_t value) |
172 | kfree(h_entry->key); | 319 | { |
173 | hash_del(&h_entry->hlist); | 320 | int err; |
174 | kmem_cache_free(hashtable_entry_cachep, h_entry); | 321 | |
322 | mutex_lock(&sdcardfs_super_list_lock); | ||
323 | err = insert_ext_gid_entry_locked(key, value); | ||
324 | mutex_unlock(&sdcardfs_super_list_lock); | ||
325 | |||
326 | return err; | ||
175 | } | 327 | } |
176 | 328 | ||
177 | static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key) | 329 | static int insert_userid_exclude_entry(const struct qstr *key, userid_t value) |
178 | { | 330 | { |
179 | struct sdcardfs_sb_info *sbinfo; | 331 | int err; |
180 | struct hashtable_entry *hash_cur; | 332 | |
181 | unsigned int hash = str_hash(key); | ||
182 | mutex_lock(&sdcardfs_super_list_lock); | 333 | mutex_lock(&sdcardfs_super_list_lock); |
183 | mutex_lock(&pkgl_dat->hashtable_lock); | 334 | err = insert_userid_exclude_entry_locked(key, value); |
184 | hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { | 335 | if (!err) |
185 | if (!strcasecmp(key, hash_cur->key)) { | 336 | fixup_all_perms_name_userid(key, value); |
186 | remove_str_to_int_lock(hash_cur); | 337 | mutex_unlock(&sdcardfs_super_list_lock); |
338 | |||
339 | return err; | ||
340 | } | ||
341 | |||
342 | static void free_hashtable_entry(struct hashtable_entry *entry) | ||
343 | { | ||
344 | kfree(entry->key.name); | ||
345 | kmem_cache_free(hashtable_entry_cachep, entry); | ||
346 | } | ||
347 | |||
348 | static void remove_packagelist_entry_locked(const struct qstr *key) | ||
349 | { | ||
350 | struct hashtable_entry *hash_cur; | ||
351 | unsigned int hash = key->hash; | ||
352 | struct hlist_node *h_t; | ||
353 | HLIST_HEAD(free_list); | ||
354 | |||
355 | hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { | ||
356 | if (qstr_case_eq(key, &hash_cur->key)) { | ||
357 | hash_del_rcu(&hash_cur->hlist); | ||
358 | hlist_add_head(&hash_cur->dlist, &free_list); | ||
359 | } | ||
360 | } | ||
361 | hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { | ||
362 | if (qstr_case_eq(key, &hash_cur->key)) { | ||
363 | hash_del_rcu(&hash_cur->hlist); | ||
364 | hlist_add_head(&hash_cur->dlist, &free_list); | ||
187 | break; | 365 | break; |
188 | } | 366 | } |
189 | } | 367 | } |
190 | mutex_unlock(&pkgl_dat->hashtable_lock); | 368 | synchronize_rcu(); |
191 | list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { | 369 | hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) |
192 | if (sbinfo) { | 370 | free_hashtable_entry(hash_cur); |
193 | fixup_perms(sbinfo->sb); | 371 | } |
372 | |||
373 | static void remove_packagelist_entry(const struct qstr *key) | ||
374 | { | ||
375 | mutex_lock(&sdcardfs_super_list_lock); | ||
376 | remove_packagelist_entry_locked(key); | ||
377 | fixup_all_perms_name(key); | ||
378 | mutex_unlock(&sdcardfs_super_list_lock); | ||
379 | } | ||
380 | |||
381 | static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) | ||
382 | { | ||
383 | struct hashtable_entry *hash_cur; | ||
384 | unsigned int hash = key->hash; | ||
385 | |||
386 | hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { | ||
387 | if (qstr_case_eq(key, &hash_cur->key) && atomic_read(&hash_cur->value) == group) { | ||
388 | hash_del_rcu(&hash_cur->hlist); | ||
389 | synchronize_rcu(); | ||
390 | free_hashtable_entry(hash_cur); | ||
391 | break; | ||
194 | } | 392 | } |
195 | } | 393 | } |
394 | } | ||
395 | |||
396 | static void remove_ext_gid_entry(const struct qstr *key, gid_t group) | ||
397 | { | ||
398 | mutex_lock(&sdcardfs_super_list_lock); | ||
399 | remove_ext_gid_entry_locked(key, group); | ||
196 | mutex_unlock(&sdcardfs_super_list_lock); | 400 | mutex_unlock(&sdcardfs_super_list_lock); |
197 | return; | ||
198 | } | 401 | } |
199 | 402 | ||
200 | static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) | 403 | static void remove_userid_all_entry_locked(userid_t userid) |
201 | { | 404 | { |
202 | struct hashtable_entry *hash_cur; | 405 | struct hashtable_entry *hash_cur; |
203 | struct hlist_node *h_t; | 406 | struct hlist_node *h_t; |
407 | HLIST_HEAD(free_list); | ||
204 | int i; | 408 | int i; |
205 | mutex_lock(&pkgl_dat->hashtable_lock); | 409 | |
206 | hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) | 410 | hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { |
207 | remove_str_to_int_lock(hash_cur); | 411 | if (atomic_read(&hash_cur->value) == userid) { |
208 | mutex_unlock(&pkgl_dat->hashtable_lock); | 412 | hash_del_rcu(&hash_cur->hlist); |
209 | hash_init(pkgl_dat->package_to_appid); | 413 | hlist_add_head(&hash_cur->dlist, &free_list); |
414 | } | ||
415 | } | ||
416 | synchronize_rcu(); | ||
417 | hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) { | ||
418 | free_hashtable_entry(hash_cur); | ||
419 | } | ||
210 | } | 420 | } |
211 | 421 | ||
212 | static struct packagelist_data * packagelist_create(void) | 422 | static void remove_userid_all_entry(userid_t userid) |
213 | { | 423 | { |
214 | struct packagelist_data *pkgl_dat; | 424 | mutex_lock(&sdcardfs_super_list_lock); |
425 | remove_userid_all_entry_locked(userid); | ||
426 | fixup_all_perms_userid(userid); | ||
427 | mutex_unlock(&sdcardfs_super_list_lock); | ||
428 | } | ||
215 | 429 | ||
216 | pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); | 430 | static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t userid) |
217 | if (!pkgl_dat) { | 431 | { |
218 | printk(KERN_ERR "sdcardfs: Failed to create hash\n"); | 432 | struct hashtable_entry *hash_cur; |
219 | return ERR_PTR(-ENOMEM); | 433 | unsigned int hash = key->hash; |
434 | |||
435 | hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { | ||
436 | if (qstr_case_eq(key, &hash_cur->key) && | ||
437 | atomic_read(&hash_cur->value) == userid) { | ||
438 | hash_del_rcu(&hash_cur->hlist); | ||
439 | synchronize_rcu(); | ||
440 | free_hashtable_entry(hash_cur); | ||
441 | break; | ||
442 | } | ||
220 | } | 443 | } |
444 | } | ||
221 | 445 | ||
222 | mutex_init(&pkgl_dat->hashtable_lock); | 446 | static void remove_userid_exclude_entry(const struct qstr *key, userid_t userid) |
223 | hash_init(pkgl_dat->package_to_appid); | 447 | { |
224 | 448 | mutex_lock(&sdcardfs_super_list_lock); | |
225 | return pkgl_dat; | 449 | remove_userid_exclude_entry_locked(key, userid); |
450 | fixup_all_perms_name_userid(key, userid); | ||
451 | mutex_unlock(&sdcardfs_super_list_lock); | ||
226 | } | 452 | } |
227 | 453 | ||
228 | static void packagelist_destroy(struct packagelist_data *pkgl_dat) | 454 | static void packagelist_destroy(void) |
229 | { | 455 | { |
230 | remove_all_hashentrys(pkgl_dat); | 456 | struct hashtable_entry *hash_cur; |
231 | printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); | 457 | struct hlist_node *h_t; |
232 | kfree(pkgl_dat); | 458 | HLIST_HEAD(free_list); |
459 | int i; | ||
460 | |||
461 | mutex_lock(&sdcardfs_super_list_lock); | ||
462 | hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { | ||
463 | hash_del_rcu(&hash_cur->hlist); | ||
464 | hlist_add_head(&hash_cur->dlist, &free_list); | ||
465 | } | ||
466 | hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { | ||
467 | hash_del_rcu(&hash_cur->hlist); | ||
468 | hlist_add_head(&hash_cur->dlist, &free_list); | ||
469 | } | ||
470 | synchronize_rcu(); | ||
471 | hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) | ||
472 | free_hashtable_entry(hash_cur); | ||
473 | mutex_unlock(&sdcardfs_super_list_lock); | ||
474 | pr_info("sdcardfs: destroyed packagelist pkgld\n"); | ||
475 | } | ||
476 | |||
477 | #define SDCARDFS_CONFIGFS_ATTR(_pfx, _name) \ | ||
478 | static struct configfs_attribute _pfx##attr_##_name = { \ | ||
479 | .ca_name = __stringify(_name), \ | ||
480 | .ca_mode = S_IRUGO | S_IWUGO, \ | ||
481 | .ca_owner = THIS_MODULE, \ | ||
482 | .show = _pfx##_name##_show, \ | ||
483 | .store = _pfx##_name##_store, \ | ||
484 | } | ||
485 | |||
486 | #define SDCARDFS_CONFIGFS_ATTR_RO(_pfx, _name) \ | ||
487 | static struct configfs_attribute _pfx##attr_##_name = { \ | ||
488 | .ca_name = __stringify(_name), \ | ||
489 | .ca_mode = S_IRUGO, \ | ||
490 | .ca_owner = THIS_MODULE, \ | ||
491 | .show = _pfx##_name##_show, \ | ||
492 | } | ||
493 | |||
494 | #define SDCARDFS_CONFIGFS_ATTR_WO(_pfx, _name) \ | ||
495 | static struct configfs_attribute _pfx##attr_##_name = { \ | ||
496 | .ca_name = __stringify(_name), \ | ||
497 | .ca_mode = S_IWUGO, \ | ||
498 | .ca_owner = THIS_MODULE, \ | ||
499 | .store = _pfx##_name##_store, \ | ||
233 | } | 500 | } |
234 | 501 | ||
235 | struct package_appid { | 502 | struct package_details { |
236 | struct config_item item; | 503 | struct config_item item; |
237 | int add_pid; | 504 | struct qstr name; |
238 | }; | 505 | }; |
239 | 506 | ||
240 | static inline struct package_appid *to_package_appid(struct config_item *item) | 507 | static inline struct package_details *to_package_details(struct config_item *item) |
241 | { | 508 | { |
242 | return item ? container_of(item, struct package_appid, item) : NULL; | 509 | return item ? container_of(item, struct package_details, item) : NULL; |
510 | } | ||
511 | |||
512 | static ssize_t package_details_appid_show(struct config_item *item, char *page) | ||
513 | { | ||
514 | return scnprintf(page, PAGE_SIZE, "%u\n", __get_appid(&to_package_details(item)->name)); | ||
515 | } | ||
516 | |||
517 | static ssize_t package_details_appid_store(struct config_item *item, | ||
518 | const char *page, size_t count) | ||
519 | { | ||
520 | unsigned int tmp; | ||
521 | int ret; | ||
522 | |||
523 | ret = kstrtouint(page, 10, &tmp); | ||
524 | if (ret) | ||
525 | return ret; | ||
526 | |||
527 | ret = insert_packagelist_entry(&to_package_details(item)->name, tmp); | ||
528 | |||
529 | if (ret) | ||
530 | return ret; | ||
531 | |||
532 | return count; | ||
243 | } | 533 | } |
244 | 534 | ||
245 | static ssize_t package_appid_attr_show(struct config_item *item, | 535 | static ssize_t package_details_excluded_userids_show(struct config_item *item, |
246 | char *page) | 536 | char *page) |
247 | { | 537 | { |
248 | ssize_t count; | 538 | struct package_details *package_details = to_package_details(item); |
249 | count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name)); | 539 | struct hashtable_entry *hash_cur; |
540 | unsigned int hash = package_details->name.hash; | ||
541 | int count = 0; | ||
542 | |||
543 | rcu_read_lock(); | ||
544 | hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { | ||
545 | if (qstr_case_eq(&package_details->name, &hash_cur->key)) | ||
546 | count += scnprintf(page + count, PAGE_SIZE - count, | ||
547 | "%d ", atomic_read(&hash_cur->value)); | ||
548 | } | ||
549 | rcu_read_unlock(); | ||
550 | if (count) | ||
551 | count--; | ||
552 | count += scnprintf(page + count, PAGE_SIZE - count, "\n"); | ||
250 | return count; | 553 | return count; |
251 | } | 554 | } |
252 | 555 | ||
253 | static ssize_t package_appid_attr_store(struct config_item *item, | 556 | static ssize_t package_details_excluded_userids_store(struct config_item *item, |
254 | const char *page, size_t count) | 557 | const char *page, size_t count) |
255 | { | 558 | { |
256 | struct package_appid *package_appid = to_package_appid(item); | 559 | unsigned int tmp; |
257 | unsigned long tmp; | ||
258 | char *p = (char *) page; | ||
259 | int ret; | 560 | int ret; |
260 | 561 | ||
261 | tmp = simple_strtoul(p, &p, 10); | 562 | ret = kstrtouint(page, 10, &tmp); |
262 | if (!p || (*p && (*p != '\n'))) | 563 | if (ret) |
263 | return -EINVAL; | 564 | return ret; |
565 | |||
566 | ret = insert_userid_exclude_entry(&to_package_details(item)->name, tmp); | ||
264 | 567 | ||
265 | if (tmp > INT_MAX) | ||
266 | return -ERANGE; | ||
267 | ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp); | ||
268 | package_appid->add_pid = tmp; | ||
269 | if (ret) | 568 | if (ret) |
270 | return ret; | 569 | return ret; |
271 | 570 | ||
272 | return count; | 571 | return count; |
273 | } | 572 | } |
274 | 573 | ||
275 | static struct configfs_attribute package_appid_attr_add_pid = { | 574 | static ssize_t package_details_clear_userid_store(struct config_item *item, |
276 | .ca_owner = THIS_MODULE, | 575 | const char *page, size_t count) |
277 | .ca_name = "appid", | 576 | { |
278 | .ca_mode = S_IRUGO | S_IWUGO, | 577 | unsigned int tmp; |
279 | .show = package_appid_attr_show, | 578 | int ret; |
280 | .store = package_appid_attr_store, | ||
281 | }; | ||
282 | 579 | ||
283 | static struct configfs_attribute *package_appid_attrs[] = { | 580 | ret = kstrtouint(page, 10, &tmp); |
284 | &package_appid_attr_add_pid, | 581 | if (ret) |
285 | NULL, | 582 | return ret; |
286 | }; | 583 | remove_userid_exclude_entry(&to_package_details(item)->name, tmp); |
584 | return count; | ||
585 | } | ||
287 | 586 | ||
288 | static void package_appid_release(struct config_item *item) | 587 | static void package_details_release(struct config_item *item) |
289 | { | 588 | { |
290 | printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name); | 589 | struct package_details *package_details = to_package_details(item); |
291 | /* item->ci_name is freed already, so we rely on the dentry */ | 590 | |
292 | remove_str_to_int(pkgl_data_all, item->ci_dentry->d_name.name); | 591 | pr_info("sdcardfs: removing %s\n", package_details->name.name); |
293 | kfree(to_package_appid(item)); | 592 | remove_packagelist_entry(&package_details->name); |
593 | kfree(package_details->name.name); | ||
594 | kfree(package_details); | ||
294 | } | 595 | } |
295 | 596 | ||
296 | static struct configfs_item_operations package_appid_item_ops = { | 597 | SDCARDFS_CONFIGFS_ATTR(package_details_, appid); |
297 | .release = package_appid_release, | 598 | SDCARDFS_CONFIGFS_ATTR(package_details_, excluded_userids); |
599 | SDCARDFS_CONFIGFS_ATTR_WO(package_details_, clear_userid); | ||
600 | |||
601 | static struct configfs_attribute *package_details_attrs[] = { | ||
602 | &package_details_attr_appid, | ||
603 | &package_details_attr_excluded_userids, | ||
604 | &package_details_attr_clear_userid, | ||
605 | NULL, | ||
606 | }; | ||
607 | |||
608 | static struct configfs_item_operations package_details_item_ops = { | ||
609 | .release = package_details_release, | ||
298 | }; | 610 | }; |
299 | 611 | ||
300 | static struct config_item_type package_appid_type = { | 612 | static struct config_item_type package_appid_type = { |
301 | .ct_item_ops = &package_appid_item_ops, | 613 | .ct_item_ops = &package_details_item_ops, |
302 | .ct_attrs = package_appid_attrs, | 614 | .ct_attrs = package_details_attrs, |
303 | .ct_owner = THIS_MODULE, | 615 | .ct_owner = THIS_MODULE, |
304 | }; | 616 | }; |
305 | 617 | ||
306 | 618 | struct extensions_value { | |
307 | struct sdcardfs_packages { | ||
308 | struct config_group group; | 619 | struct config_group group; |
620 | unsigned int num; | ||
621 | }; | ||
622 | |||
623 | struct extension_details { | ||
624 | struct config_item item; | ||
625 | struct qstr name; | ||
626 | unsigned int num; | ||
627 | }; | ||
628 | |||
629 | static inline struct extensions_value *to_extensions_value(struct config_item *item) | ||
630 | { | ||
631 | return item ? container_of(to_config_group(item), struct extensions_value, group) : NULL; | ||
632 | } | ||
633 | |||
634 | static inline struct extension_details *to_extension_details(struct config_item *item) | ||
635 | { | ||
636 | return item ? container_of(item, struct extension_details, item) : NULL; | ||
637 | } | ||
638 | |||
639 | static void extension_details_release(struct config_item *item) | ||
640 | { | ||
641 | struct extension_details *extension_details = to_extension_details(item); | ||
642 | |||
643 | pr_info("sdcardfs: No longer mapping %s files to gid %d\n", | ||
644 | extension_details->name.name, extension_details->num); | ||
645 | remove_ext_gid_entry(&extension_details->name, extension_details->num); | ||
646 | kfree(extension_details->name.name); | ||
647 | kfree(extension_details); | ||
648 | } | ||
649 | |||
650 | static struct configfs_item_operations extension_details_item_ops = { | ||
651 | .release = extension_details_release, | ||
652 | }; | ||
653 | |||
654 | static struct config_item_type extension_details_type = { | ||
655 | .ct_item_ops = &extension_details_item_ops, | ||
656 | .ct_owner = THIS_MODULE, | ||
309 | }; | 657 | }; |
310 | 658 | ||
311 | static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item) | 659 | static struct config_item *extension_details_make_item(struct config_group *group, const char *name) |
312 | { | 660 | { |
313 | return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL; | 661 | struct extensions_value *extensions_value = to_extensions_value(&group->cg_item); |
662 | struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL); | ||
663 | const char *tmp; | ||
664 | int ret; | ||
665 | |||
666 | if (!extension_details) | ||
667 | return ERR_PTR(-ENOMEM); | ||
668 | |||
669 | tmp = kstrdup(name, GFP_KERNEL); | ||
670 | if (!tmp) { | ||
671 | kfree(extension_details); | ||
672 | return ERR_PTR(-ENOMEM); | ||
673 | } | ||
674 | qstr_init(&extension_details->name, tmp); | ||
675 | ret = insert_ext_gid_entry(&extension_details->name, extensions_value->num); | ||
676 | |||
677 | if (ret) { | ||
678 | kfree(extension_details->name.name); | ||
679 | kfree(extension_details); | ||
680 | return ERR_PTR(ret); | ||
681 | } | ||
682 | config_item_init_type_name(&extension_details->item, name, &extension_details_type); | ||
683 | |||
684 | return &extension_details->item; | ||
314 | } | 685 | } |
315 | 686 | ||
316 | static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name) | 687 | static struct configfs_group_operations extensions_value_group_ops = { |
688 | .make_item = extension_details_make_item, | ||
689 | }; | ||
690 | |||
691 | static struct config_item_type extensions_name_type = { | ||
692 | .ct_group_ops = &extensions_value_group_ops, | ||
693 | .ct_owner = THIS_MODULE, | ||
694 | }; | ||
695 | |||
696 | static struct config_group *extensions_make_group(struct config_group *group, const char *name) | ||
317 | { | 697 | { |
318 | struct package_appid *package_appid; | 698 | struct extensions_value *extensions_value; |
699 | unsigned int tmp; | ||
700 | int ret; | ||
319 | 701 | ||
320 | package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL); | 702 | extensions_value = kzalloc(sizeof(struct extensions_value), GFP_KERNEL); |
321 | if (!package_appid) | 703 | if (!extensions_value) |
322 | return ERR_PTR(-ENOMEM); | 704 | return ERR_PTR(-ENOMEM); |
705 | ret = kstrtouint(name, 10, &tmp); | ||
706 | if (ret) { | ||
707 | kfree(extensions_value); | ||
708 | return ERR_PTR(ret); | ||
709 | } | ||
710 | |||
711 | extensions_value->num = tmp; | ||
712 | config_group_init_type_name(&extensions_value->group, name, | ||
713 | &extensions_name_type); | ||
714 | return &extensions_value->group; | ||
715 | } | ||
716 | |||
717 | static void extensions_drop_group(struct config_group *group, struct config_item *item) | ||
718 | { | ||
719 | struct extensions_value *value = to_extensions_value(item); | ||
720 | |||
721 | pr_info("sdcardfs: No longer mapping any files to gid %d\n", value->num); | ||
722 | kfree(value); | ||
723 | } | ||
724 | |||
725 | static struct configfs_group_operations extensions_group_ops = { | ||
726 | .make_group = extensions_make_group, | ||
727 | .drop_item = extensions_drop_group, | ||
728 | }; | ||
323 | 729 | ||
324 | config_item_init_type_name(&package_appid->item, name, | 730 | static struct config_item_type extensions_type = { |
325 | &package_appid_type); | 731 | .ct_group_ops = &extensions_group_ops, |
732 | .ct_owner = THIS_MODULE, | ||
733 | }; | ||
326 | 734 | ||
327 | package_appid->add_pid = 0; | 735 | struct config_group extension_group = { |
736 | .cg_item = { | ||
737 | .ci_namebuf = "extensions", | ||
738 | .ci_type = &extensions_type, | ||
739 | }, | ||
740 | }; | ||
328 | 741 | ||
329 | return &package_appid->item; | 742 | static struct config_item *packages_make_item(struct config_group *group, const char *name) |
743 | { | ||
744 | struct package_details *package_details; | ||
745 | const char *tmp; | ||
746 | |||
747 | package_details = kzalloc(sizeof(struct package_details), GFP_KERNEL); | ||
748 | if (!package_details) | ||
749 | return ERR_PTR(-ENOMEM); | ||
750 | tmp = kstrdup(name, GFP_KERNEL); | ||
751 | if (!tmp) { | ||
752 | kfree(package_details); | ||
753 | return ERR_PTR(-ENOMEM); | ||
754 | } | ||
755 | qstr_init(&package_details->name, tmp); | ||
756 | config_item_init_type_name(&package_details->item, name, | ||
757 | &package_appid_type); | ||
758 | |||
759 | return &package_details->item; | ||
330 | } | 760 | } |
331 | 761 | ||
332 | static ssize_t packages_attr_show(struct config_item *item, | 762 | static ssize_t packages_list_show(struct config_item *item, char *page) |
333 | char *page) | ||
334 | { | 763 | { |
335 | struct hashtable_entry *hash_cur; | 764 | struct hashtable_entry *hash_cur_app; |
336 | struct hlist_node *h_t; | 765 | struct hashtable_entry *hash_cur_user; |
337 | int i; | 766 | int i; |
338 | int count = 0, written = 0; | 767 | int count = 0, written = 0; |
339 | char errormsg[] = "<truncated>\n"; | 768 | const char errormsg[] = "<truncated>\n"; |
340 | 769 | unsigned int hash; | |
341 | mutex_lock(&pkgl_data_all->hashtable_lock); | 770 | |
342 | hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) { | 771 | rcu_read_lock(); |
343 | written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); | 772 | hash_for_each_rcu(package_to_appid, i, hash_cur_app, hlist) { |
344 | if (count + written == PAGE_SIZE - sizeof(errormsg)) { | 773 | written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", |
774 | hash_cur_app->key.name, atomic_read(&hash_cur_app->value)); | ||
775 | hash = hash_cur_app->key.hash; | ||
776 | hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) { | ||
777 | if (qstr_case_eq(&hash_cur_app->key, &hash_cur_user->key)) { | ||
778 | written += scnprintf(page + count + written - 1, | ||
779 | PAGE_SIZE - sizeof(errormsg) - count - written + 1, | ||
780 | " %d\n", atomic_read(&hash_cur_user->value)) - 1; | ||
781 | } | ||
782 | } | ||
783 | if (count + written == PAGE_SIZE - sizeof(errormsg) - 1) { | ||
345 | count += scnprintf(page + count, PAGE_SIZE - count, errormsg); | 784 | count += scnprintf(page + count, PAGE_SIZE - count, errormsg); |
346 | break; | 785 | break; |
347 | } | 786 | } |
348 | count += written; | 787 | count += written; |
349 | } | 788 | } |
350 | mutex_unlock(&pkgl_data_all->hashtable_lock); | 789 | rcu_read_unlock(); |
351 | 790 | ||
352 | return count; | 791 | return count; |
353 | } | 792 | } |
354 | 793 | ||
355 | static struct configfs_attribute sdcardfs_packages_attr_description = { | 794 | static ssize_t packages_remove_userid_store(struct config_item *item, |
356 | .ca_owner = THIS_MODULE, | 795 | const char *page, size_t count) |
357 | .ca_name = "packages_gid.list", | ||
358 | .ca_mode = S_IRUGO, | ||
359 | .show = packages_attr_show, | ||
360 | }; | ||
361 | |||
362 | static struct configfs_attribute *sdcardfs_packages_attrs[] = { | ||
363 | &sdcardfs_packages_attr_description, | ||
364 | NULL, | ||
365 | }; | ||
366 | |||
367 | static void sdcardfs_packages_release(struct config_item *item) | ||
368 | { | 796 | { |
797 | unsigned int tmp; | ||
798 | int ret; | ||
369 | 799 | ||
370 | printk(KERN_INFO "sdcardfs: destroyed something?\n"); | 800 | ret = kstrtouint(page, 10, &tmp); |
371 | kfree(to_sdcardfs_packages(item)); | 801 | if (ret) |
802 | return ret; | ||
803 | remove_userid_all_entry(tmp); | ||
804 | return count; | ||
372 | } | 805 | } |
373 | 806 | ||
374 | static struct configfs_item_operations sdcardfs_packages_item_ops = { | 807 | static struct configfs_attribute packages_attr_packages_gid_list = { |
375 | .release = sdcardfs_packages_release, | 808 | .ca_name = "packages_gid.list", |
809 | .ca_mode = S_IRUGO, | ||
810 | .ca_owner = THIS_MODULE, | ||
811 | .show = packages_list_show, | ||
812 | }; | ||
813 | |||
814 | SDCARDFS_CONFIGFS_ATTR_WO(packages_, remove_userid); | ||
815 | |||
816 | static struct configfs_attribute *packages_attrs[] = { | ||
817 | &packages_attr_packages_gid_list, | ||
818 | &packages_attr_remove_userid, | ||
819 | NULL, | ||
376 | }; | 820 | }; |
377 | 821 | ||
378 | /* | 822 | /* |
379 | * Note that, since no extra work is required on ->drop_item(), | 823 | * Note that, since no extra work is required on ->drop_item(), |
380 | * no ->drop_item() is provided. | 824 | * no ->drop_item() is provided. |
381 | */ | 825 | */ |
382 | static struct configfs_group_operations sdcardfs_packages_group_ops = { | 826 | static struct configfs_group_operations packages_group_ops = { |
383 | .make_item = sdcardfs_packages_make_item, | 827 | .make_item = packages_make_item, |
384 | }; | 828 | }; |
385 | 829 | ||
386 | static struct config_item_type sdcardfs_packages_type = { | 830 | static struct config_item_type packages_type = { |
387 | .ct_item_ops = &sdcardfs_packages_item_ops, | 831 | .ct_group_ops = &packages_group_ops, |
388 | .ct_group_ops = &sdcardfs_packages_group_ops, | 832 | .ct_attrs = packages_attrs, |
389 | .ct_attrs = sdcardfs_packages_attrs, | ||
390 | .ct_owner = THIS_MODULE, | 833 | .ct_owner = THIS_MODULE, |
391 | }; | 834 | }; |
392 | 835 | ||
393 | static struct configfs_subsystem sdcardfs_packages_subsys = { | 836 | struct config_group *sd_default_groups[] = { |
837 | &extension_group, | ||
838 | NULL, | ||
839 | }; | ||
840 | |||
841 | static struct configfs_subsystem sdcardfs_packages = { | ||
394 | .su_group = { | 842 | .su_group = { |
395 | .cg_item = { | 843 | .cg_item = { |
396 | .ci_namebuf = "sdcardfs", | 844 | .ci_namebuf = "sdcardfs", |
397 | .ci_type = &sdcardfs_packages_type, | 845 | .ci_type = &packages_type, |
398 | }, | 846 | }, |
847 | .default_groups = sd_default_groups, | ||
399 | }, | 848 | }, |
400 | }; | 849 | }; |
401 | 850 | ||
402 | static int configfs_sdcardfs_init(void) | 851 | static int configfs_sdcardfs_init(void) |
403 | { | 852 | { |
404 | int ret; | 853 | int ret, i; |
405 | struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; | 854 | struct configfs_subsystem *subsys = &sdcardfs_packages; |
406 | 855 | ||
856 | for (i = 0; sd_default_groups[i]; i++) | ||
857 | config_group_init(sd_default_groups[i]); | ||
407 | config_group_init(&subsys->su_group); | 858 | config_group_init(&subsys->su_group); |
408 | mutex_init(&subsys->su_mutex); | 859 | mutex_init(&subsys->su_mutex); |
409 | ret = configfs_register_subsystem(subsys); | 860 | ret = configfs_register_subsystem(subsys); |
410 | if (ret) { | 861 | if (ret) { |
411 | printk(KERN_ERR "Error %d while registering subsystem %s\n", | 862 | pr_err("Error %d while registering subsystem %s\n", |
412 | ret, | 863 | ret, |
413 | subsys->su_group.cg_item.ci_namebuf); | 864 | subsys->su_group.cg_item.ci_namebuf); |
414 | } | 865 | } |
@@ -417,7 +868,7 @@ static int configfs_sdcardfs_init(void) | |||
417 | 868 | ||
418 | static void configfs_sdcardfs_exit(void) | 869 | static void configfs_sdcardfs_exit(void) |
419 | { | 870 | { |
420 | configfs_unregister_subsystem(&sdcardfs_packages_subsys); | 871 | configfs_unregister_subsystem(&sdcardfs_packages); |
421 | } | 872 | } |
422 | 873 | ||
423 | int packagelist_init(void) | 874 | int packagelist_init(void) |
@@ -426,19 +877,17 @@ int packagelist_init(void) | |||
426 | kmem_cache_create("packagelist_hashtable_entry", | 877 | kmem_cache_create("packagelist_hashtable_entry", |
427 | sizeof(struct hashtable_entry), 0, 0, NULL); | 878 | sizeof(struct hashtable_entry), 0, 0, NULL); |
428 | if (!hashtable_entry_cachep) { | 879 | if (!hashtable_entry_cachep) { |
429 | printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); | 880 | pr_err("sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); |
430 | return -ENOMEM; | 881 | return -ENOMEM; |
431 | } | 882 | } |
432 | 883 | ||
433 | pkgl_data_all = packagelist_create(); | ||
434 | configfs_sdcardfs_init(); | 884 | configfs_sdcardfs_init(); |
435 | return 0; | 885 | return 0; |
436 | } | 886 | } |
437 | 887 | ||
438 | void packagelist_exit(void) | 888 | void packagelist_exit(void) |
439 | { | 889 | { |
440 | configfs_sdcardfs_exit(); | 890 | configfs_sdcardfs_exit(); |
441 | packagelist_destroy(pkgl_data_all); | 891 | packagelist_destroy(); |
442 | if (hashtable_entry_cachep) | 892 | kmem_cache_destroy(hashtable_entry_cachep); |
443 | kmem_cache_destroy(hashtable_entry_cachep); | ||
444 | } | 893 | } |