diff options
author | Abhishek Kulkarni <adkulkar@umail.iu.edu> | 2009-09-23 14:00:27 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@strongmad.austin.ibm.com> | 2009-09-23 14:03:46 -0400 |
commit | 60e78d2c993e58d890596d951fff77d5965adcd6 (patch) | |
tree | 3d53ed7254c613ef8d8de36fdceda25bc493f4f7 /fs/9p/v9fs.c | |
parent | 637d020a02cd734bf27acfc56c6d942cddd9eb80 (diff) |
9p: Add fscache support to 9p
This patch adds a persistent, read-only caching facility for
9p clients using the FS-Cache caching backend.
When the fscache facility is enabled, each inode is associated
with a corresponding vcookie which is an index into the FS-Cache
indexing tree. The FS-Cache indexing tree is indexed at 3 levels:
- session object associated with each mount.
- inode/vcookie
- actual data (pages)
A cache tag is chosen randomly for each session. These tags can
be read off /sys/fs/9p/caches and can be passed as a mount-time
parameter to re-attach to the specified caching session.
Signed-off-by: Abhishek Kulkarni <adkulkar@umail.iu.edu>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'fs/9p/v9fs.c')
-rw-r--r-- | fs/9p/v9fs.c | 196 |
1 files changed, 175 insertions, 21 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index f7003cfac63d..cf62b05e296a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -34,21 +34,25 @@ | |||
34 | #include <net/9p/transport.h> | 34 | #include <net/9p/transport.h> |
35 | #include "v9fs.h" | 35 | #include "v9fs.h" |
36 | #include "v9fs_vfs.h" | 36 | #include "v9fs_vfs.h" |
37 | #include "cache.h" | ||
38 | |||
39 | static DEFINE_SPINLOCK(v9fs_sessionlist_lock); | ||
40 | static LIST_HEAD(v9fs_sessionlist); | ||
37 | 41 | ||
38 | /* | 42 | /* |
39 | * Option Parsing (code inspired by NFS code) | 43 | * Option Parsing (code inspired by NFS code) |
40 | * NOTE: each transport will parse its own options | 44 | * NOTE: each transport will parse its own options |
41 | */ | 45 | */ |
42 | 46 | ||
43 | enum { | 47 | enum { |
44 | /* Options that take integer arguments */ | 48 | /* Options that take integer arguments */ |
45 | Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, | 49 | Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, |
46 | /* String options */ | 50 | /* String options */ |
47 | Opt_uname, Opt_remotename, Opt_trans, | 51 | Opt_uname, Opt_remotename, Opt_trans, Opt_cache, Opt_cachetag, |
48 | /* Options that take no arguments */ | 52 | /* Options that take no arguments */ |
49 | Opt_nodevmap, | 53 | Opt_nodevmap, |
50 | /* Cache options */ | 54 | /* Cache options */ |
51 | Opt_cache_loose, | 55 | Opt_cache_loose, Opt_fscache, |
52 | /* Access options */ | 56 | /* Access options */ |
53 | Opt_access, | 57 | Opt_access, |
54 | /* Error token */ | 58 | /* Error token */ |
@@ -63,8 +67,10 @@ static const match_table_t tokens = { | |||
63 | {Opt_uname, "uname=%s"}, | 67 | {Opt_uname, "uname=%s"}, |
64 | {Opt_remotename, "aname=%s"}, | 68 | {Opt_remotename, "aname=%s"}, |
65 | {Opt_nodevmap, "nodevmap"}, | 69 | {Opt_nodevmap, "nodevmap"}, |
66 | {Opt_cache_loose, "cache=loose"}, | 70 | {Opt_cache, "cache=%s"}, |
67 | {Opt_cache_loose, "loose"}, | 71 | {Opt_cache_loose, "loose"}, |
72 | {Opt_fscache, "fscache"}, | ||
73 | {Opt_cachetag, "cachetag=%s"}, | ||
68 | {Opt_access, "access=%s"}, | 74 | {Opt_access, "access=%s"}, |
69 | {Opt_err, NULL} | 75 | {Opt_err, NULL} |
70 | }; | 76 | }; |
@@ -89,16 +95,16 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
89 | v9ses->afid = ~0; | 95 | v9ses->afid = ~0; |
90 | v9ses->debug = 0; | 96 | v9ses->debug = 0; |
91 | v9ses->cache = 0; | 97 | v9ses->cache = 0; |
98 | #ifdef CONFIG_9P_FSCACHE | ||
99 | v9ses->cachetag = NULL; | ||
100 | #endif | ||
92 | 101 | ||
93 | if (!opts) | 102 | if (!opts) |
94 | return 0; | 103 | return 0; |
95 | 104 | ||
96 | options = kstrdup(opts, GFP_KERNEL); | 105 | options = kstrdup(opts, GFP_KERNEL); |
97 | if (!options) { | 106 | if (!options) |
98 | P9_DPRINTK(P9_DEBUG_ERROR, | 107 | goto fail_option_alloc; |
99 | "failed to allocate copy of option string\n"); | ||
100 | return -ENOMEM; | ||
101 | } | ||
102 | 108 | ||
103 | while ((p = strsep(&options, ",")) != NULL) { | 109 | while ((p = strsep(&options, ",")) != NULL) { |
104 | int token; | 110 | int token; |
@@ -143,16 +149,33 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
143 | case Opt_cache_loose: | 149 | case Opt_cache_loose: |
144 | v9ses->cache = CACHE_LOOSE; | 150 | v9ses->cache = CACHE_LOOSE; |
145 | break; | 151 | break; |
152 | case Opt_fscache: | ||
153 | v9ses->cache = CACHE_FSCACHE; | ||
154 | break; | ||
155 | case Opt_cachetag: | ||
156 | #ifdef CONFIG_9P_FSCACHE | ||
157 | v9ses->cachetag = match_strdup(&args[0]); | ||
158 | #endif | ||
159 | break; | ||
160 | case Opt_cache: | ||
161 | s = match_strdup(&args[0]); | ||
162 | if (!s) | ||
163 | goto fail_option_alloc; | ||
164 | |||
165 | if (strcmp(s, "loose") == 0) | ||
166 | v9ses->cache = CACHE_LOOSE; | ||
167 | else if (strcmp(s, "fscache") == 0) | ||
168 | v9ses->cache = CACHE_FSCACHE; | ||
169 | else | ||
170 | v9ses->cache = CACHE_NONE; | ||
171 | kfree(s); | ||
172 | break; | ||
146 | 173 | ||
147 | case Opt_access: | 174 | case Opt_access: |
148 | s = match_strdup(&args[0]); | 175 | s = match_strdup(&args[0]); |
149 | if (!s) { | 176 | if (!s) |
150 | P9_DPRINTK(P9_DEBUG_ERROR, | 177 | goto fail_option_alloc; |
151 | "failed to allocate copy" | 178 | |
152 | " of option argument\n"); | ||
153 | ret = -ENOMEM; | ||
154 | break; | ||
155 | } | ||
156 | v9ses->flags &= ~V9FS_ACCESS_MASK; | 179 | v9ses->flags &= ~V9FS_ACCESS_MASK; |
157 | if (strcmp(s, "user") == 0) | 180 | if (strcmp(s, "user") == 0) |
158 | v9ses->flags |= V9FS_ACCESS_USER; | 181 | v9ses->flags |= V9FS_ACCESS_USER; |
@@ -173,6 +196,11 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
173 | } | 196 | } |
174 | kfree(options); | 197 | kfree(options); |
175 | return ret; | 198 | return ret; |
199 | |||
200 | fail_option_alloc: | ||
201 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
202 | "failed to allocate copy of option argument\n"); | ||
203 | return -ENOMEM; | ||
176 | } | 204 | } |
177 | 205 | ||
178 | /** | 206 | /** |
@@ -200,6 +228,10 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
200 | return ERR_PTR(-ENOMEM); | 228 | return ERR_PTR(-ENOMEM); |
201 | } | 229 | } |
202 | 230 | ||
231 | spin_lock(&v9fs_sessionlist_lock); | ||
232 | list_add(&v9ses->slist, &v9fs_sessionlist); | ||
233 | spin_unlock(&v9fs_sessionlist_lock); | ||
234 | |||
203 | v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; | 235 | v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; |
204 | strcpy(v9ses->uname, V9FS_DEFUSER); | 236 | strcpy(v9ses->uname, V9FS_DEFUSER); |
205 | strcpy(v9ses->aname, V9FS_DEFANAME); | 237 | strcpy(v9ses->aname, V9FS_DEFANAME); |
@@ -249,6 +281,11 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
249 | else | 281 | else |
250 | fid->uid = ~0; | 282 | fid->uid = ~0; |
251 | 283 | ||
284 | #ifdef CONFIG_9P_FSCACHE | ||
285 | /* register the session for caching */ | ||
286 | v9fs_cache_session_get_cookie(v9ses); | ||
287 | #endif | ||
288 | |||
252 | return fid; | 289 | return fid; |
253 | 290 | ||
254 | error: | 291 | error: |
@@ -268,8 +305,18 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) | |||
268 | v9ses->clnt = NULL; | 305 | v9ses->clnt = NULL; |
269 | } | 306 | } |
270 | 307 | ||
308 | #ifdef CONFIG_9P_FSCACHE | ||
309 | if (v9ses->fscache) { | ||
310 | v9fs_cache_session_put_cookie(v9ses); | ||
311 | kfree(v9ses->cachetag); | ||
312 | } | ||
313 | #endif | ||
271 | __putname(v9ses->uname); | 314 | __putname(v9ses->uname); |
272 | __putname(v9ses->aname); | 315 | __putname(v9ses->aname); |
316 | |||
317 | spin_lock(&v9fs_sessionlist_lock); | ||
318 | list_del(&v9ses->slist); | ||
319 | spin_unlock(&v9fs_sessionlist_lock); | ||
273 | } | 320 | } |
274 | 321 | ||
275 | /** | 322 | /** |
@@ -286,25 +333,132 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses) { | |||
286 | 333 | ||
287 | extern int v9fs_error_init(void); | 334 | extern int v9fs_error_init(void); |
288 | 335 | ||
336 | static struct kobject *v9fs_kobj; | ||
337 | |||
338 | #ifdef CONFIG_9P_FSCACHE | ||
289 | /** | 339 | /** |
290 | * v9fs_init - Initialize module | 340 | * caches_show - list caches associated with a session |
341 | * | ||
342 | * Returns the size of buffer written. | ||
343 | */ | ||
344 | |||
345 | static ssize_t caches_show(struct kobject *kobj, | ||
346 | struct kobj_attribute *attr, | ||
347 | char *buf) | ||
348 | { | ||
349 | ssize_t n = 0, count = 0, limit = PAGE_SIZE; | ||
350 | struct v9fs_session_info *v9ses; | ||
351 | |||
352 | spin_lock(&v9fs_sessionlist_lock); | ||
353 | list_for_each_entry(v9ses, &v9fs_sessionlist, slist) { | ||
354 | if (v9ses->cachetag) { | ||
355 | n = snprintf(buf, limit, "%s\n", v9ses->cachetag); | ||
356 | if (n < 0) { | ||
357 | count = n; | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | count += n; | ||
362 | limit -= n; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | spin_unlock(&v9fs_sessionlist_lock); | ||
367 | return count; | ||
368 | } | ||
369 | |||
370 | static struct kobj_attribute v9fs_attr_cache = __ATTR_RO(caches); | ||
371 | #endif /* CONFIG_9P_FSCACHE */ | ||
372 | |||
373 | static struct attribute *v9fs_attrs[] = { | ||
374 | #ifdef CONFIG_9P_FSCACHE | ||
375 | &v9fs_attr_cache.attr, | ||
376 | #endif | ||
377 | NULL, | ||
378 | }; | ||
379 | |||
380 | static struct attribute_group v9fs_attr_group = { | ||
381 | .attrs = v9fs_attrs, | ||
382 | }; | ||
383 | |||
384 | /** | ||
385 | * v9fs_sysfs_init - Initialize the v9fs sysfs interface | ||
386 | * | ||
387 | */ | ||
388 | |||
389 | static int v9fs_sysfs_init(void) | ||
390 | { | ||
391 | v9fs_kobj = kobject_create_and_add("9p", fs_kobj); | ||
392 | if (!v9fs_kobj) | ||
393 | return -ENOMEM; | ||
394 | |||
395 | if (sysfs_create_group(v9fs_kobj, &v9fs_attr_group)) { | ||
396 | kobject_put(v9fs_kobj); | ||
397 | return -ENOMEM; | ||
398 | } | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * v9fs_sysfs_cleanup - Unregister the v9fs sysfs interface | ||
405 | * | ||
406 | */ | ||
407 | |||
408 | static void v9fs_sysfs_cleanup(void) | ||
409 | { | ||
410 | sysfs_remove_group(v9fs_kobj, &v9fs_attr_group); | ||
411 | kobject_put(v9fs_kobj); | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * init_v9fs - Initialize module | ||
291 | * | 416 | * |
292 | */ | 417 | */ |
293 | 418 | ||
294 | static int __init init_v9fs(void) | 419 | static int __init init_v9fs(void) |
295 | { | 420 | { |
421 | int err; | ||
296 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); | 422 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
297 | /* TODO: Setup list of registered trasnport modules */ | 423 | /* TODO: Setup list of registered trasnport modules */ |
298 | return register_filesystem(&v9fs_fs_type); | 424 | err = register_filesystem(&v9fs_fs_type); |
425 | if (err < 0) { | ||
426 | printk(KERN_ERR "Failed to register filesystem\n"); | ||
427 | return err; | ||
428 | } | ||
429 | |||
430 | err = v9fs_cache_register(); | ||
431 | if (err < 0) { | ||
432 | printk(KERN_ERR "Failed to register v9fs for caching\n"); | ||
433 | goto out_fs_unreg; | ||
434 | } | ||
435 | |||
436 | err = v9fs_sysfs_init(); | ||
437 | if (err < 0) { | ||
438 | printk(KERN_ERR "Failed to register with sysfs\n"); | ||
439 | goto out_sysfs_cleanup; | ||
440 | } | ||
441 | |||
442 | return 0; | ||
443 | |||
444 | out_sysfs_cleanup: | ||
445 | v9fs_sysfs_cleanup(); | ||
446 | |||
447 | out_fs_unreg: | ||
448 | unregister_filesystem(&v9fs_fs_type); | ||
449 | |||
450 | return err; | ||
299 | } | 451 | } |
300 | 452 | ||
301 | /** | 453 | /** |
302 | * v9fs_init - shutdown module | 454 | * exit_v9fs - shutdown module |
303 | * | 455 | * |
304 | */ | 456 | */ |
305 | 457 | ||
306 | static void __exit exit_v9fs(void) | 458 | static void __exit exit_v9fs(void) |
307 | { | 459 | { |
460 | v9fs_sysfs_cleanup(); | ||
461 | v9fs_cache_unregister(); | ||
308 | unregister_filesystem(&v9fs_fs_type); | 462 | unregister_filesystem(&v9fs_fs_type); |
309 | } | 463 | } |
310 | 464 | ||