diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cachefiles/namei.c | 13 | ||||
-rw-r--r-- | fs/cachefiles/rdwr.c | 4 | ||||
-rw-r--r-- | fs/cifs/Kconfig | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 30 | ||||
-rw-r--r-- | fs/cifs/misc.c | 20 | ||||
-rw-r--r-- | fs/fscache/Kconfig | 1 | ||||
-rw-r--r-- | fs/fscache/internal.h | 8 | ||||
-rw-r--r-- | fs/fscache/main.c | 106 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 11 | ||||
-rw-r--r-- | fs/fscache/object.c | 106 | ||||
-rw-r--r-- | fs/fscache/operation.c | 67 | ||||
-rw-r--r-- | fs/fscache/page.c | 36 | ||||
-rw-r--r-- | fs/gfs2/Kconfig | 1 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 3 | ||||
-rw-r--r-- | fs/gfs2/main.c | 14 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 8 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 54 | ||||
-rw-r--r-- | fs/gfs2/recovery.h | 6 | ||||
-rw-r--r-- | fs/gfs2/sys.c | 3 |
22 files changed, 262 insertions, 245 deletions
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index f4a7840bf42c..42c7fafc8bfe 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -37,9 +37,9 @@ void __cachefiles_printk_object(struct cachefiles_object *object, | |||
37 | 37 | ||
38 | printk(KERN_ERR "%sobject: OBJ%x\n", | 38 | printk(KERN_ERR "%sobject: OBJ%x\n", |
39 | prefix, object->fscache.debug_id); | 39 | prefix, object->fscache.debug_id); |
40 | printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n", | 40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", |
41 | prefix, fscache_object_states[object->fscache.state], | 41 | prefix, fscache_object_states[object->fscache.state], |
42 | object->fscache.flags, object->fscache.work.flags, | 42 | object->fscache.flags, work_busy(&object->fscache.work), |
43 | object->fscache.events, | 43 | object->fscache.events, |
44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | 44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); |
45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | 45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", |
@@ -212,7 +212,7 @@ wait_for_old_object: | |||
212 | 212 | ||
213 | /* if the object we're waiting for is queued for processing, | 213 | /* if the object we're waiting for is queued for processing, |
214 | * then just put ourselves on the queue behind it */ | 214 | * then just put ourselves on the queue behind it */ |
215 | if (slow_work_is_queued(&xobject->fscache.work)) { | 215 | if (work_pending(&xobject->fscache.work)) { |
216 | _debug("queue OBJ%x behind OBJ%x immediately", | 216 | _debug("queue OBJ%x behind OBJ%x immediately", |
217 | object->fscache.debug_id, | 217 | object->fscache.debug_id, |
218 | xobject->fscache.debug_id); | 218 | xobject->fscache.debug_id); |
@@ -220,8 +220,7 @@ wait_for_old_object: | |||
220 | } | 220 | } |
221 | 221 | ||
222 | /* otherwise we sleep until either the object we're waiting for | 222 | /* otherwise we sleep until either the object we're waiting for |
223 | * is done, or the slow-work facility wants the thread back to | 223 | * is done, or the fscache_object is congested */ |
224 | * do other work */ | ||
225 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | 224 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); |
226 | init_wait(&wait); | 225 | init_wait(&wait); |
227 | requeue = false; | 226 | requeue = false; |
@@ -229,8 +228,8 @@ wait_for_old_object: | |||
229 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | 228 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); |
230 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | 229 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) |
231 | break; | 230 | break; |
232 | requeue = slow_work_sleep_till_thread_needed( | 231 | |
233 | &object->fscache.work, &timeout); | 232 | requeue = fscache_object_sleep_till_congested(&timeout); |
234 | } while (timeout > 0 && !requeue); | 233 | } while (timeout > 0 && !requeue); |
235 | finish_wait(wq, &wait); | 234 | finish_wait(wq, &wait); |
236 | 235 | ||
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index 0f0d41fbb03f..0e3c0924cc3a 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -422,7 +422,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
423 | 423 | ||
424 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; | 424 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
425 | op->op.flags |= FSCACHE_OP_FAST; | 425 | op->op.flags |= FSCACHE_OP_ASYNC; |
426 | op->op.processor = cachefiles_read_copier; | 426 | op->op.processor = cachefiles_read_copier; |
427 | 427 | ||
428 | pagevec_init(&pagevec, 0); | 428 | pagevec_init(&pagevec, 0); |
@@ -729,7 +729,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
729 | pagevec_init(&pagevec, 0); | 729 | pagevec_init(&pagevec, 0); |
730 | 730 | ||
731 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; | 731 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
732 | op->op.flags |= FSCACHE_OP_FAST; | 732 | op->op.flags |= FSCACHE_OP_ASYNC; |
733 | op->op.processor = cachefiles_read_copier; | 733 | op->op.processor = cachefiles_read_copier; |
734 | 734 | ||
735 | INIT_LIST_HEAD(&backpages); | 735 | INIT_LIST_HEAD(&backpages); |
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 5739fd7f88b4..efcb3a78a327 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -2,7 +2,6 @@ config CIFS | |||
2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
3 | depends on INET | 3 | depends on INET |
4 | select NLS | 4 | select NLS |
5 | select SLOW_WORK | ||
6 | help | 5 | help |
7 | This is the client VFS module for the Common Internet File System | 6 | This is the client VFS module for the Common Internet File System |
8 | (CIFS) protocol which is the successor to the Server Message Block | 7 | (CIFS) protocol which is the successor to the Server Message Block |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8a2cf129e535..5ac541a30c1d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -939,15 +939,10 @@ init_cifs(void) | |||
939 | if (rc) | 939 | if (rc) |
940 | goto out_unregister_key_type; | 940 | goto out_unregister_key_type; |
941 | #endif | 941 | #endif |
942 | rc = slow_work_register_user(THIS_MODULE); | ||
943 | if (rc) | ||
944 | goto out_unregister_resolver_key; | ||
945 | 942 | ||
946 | return 0; | 943 | return 0; |
947 | 944 | ||
948 | out_unregister_resolver_key: | ||
949 | #ifdef CONFIG_CIFS_DFS_UPCALL | 945 | #ifdef CONFIG_CIFS_DFS_UPCALL |
950 | cifs_exit_dns_resolver(); | ||
951 | out_unregister_key_type: | 946 | out_unregister_key_type: |
952 | #endif | 947 | #endif |
953 | #ifdef CONFIG_CIFS_UPCALL | 948 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 59906146ad36..0cdfb8c32ac6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/in.h> | 22 | #include <linux/in.h> |
23 | #include <linux/in6.h> | 23 | #include <linux/in6.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/slow-work.h> | 25 | #include <linux/workqueue.h> |
26 | #include "cifs_fs_sb.h" | 26 | #include "cifs_fs_sb.h" |
27 | #include "cifsacl.h" | 27 | #include "cifsacl.h" |
28 | /* | 28 | /* |
@@ -356,7 +356,7 @@ struct cifsFileInfo { | |||
356 | atomic_t count; /* reference count */ | 356 | atomic_t count; /* reference count */ |
357 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 357 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
358 | struct cifs_search_info srch_inf; | 358 | struct cifs_search_info srch_inf; |
359 | struct slow_work oplock_break; /* slow_work job for oplock breaks */ | 359 | struct work_struct oplock_break; /* work for oplock breaks */ |
360 | }; | 360 | }; |
361 | 361 | ||
362 | /* Take a reference on the file private data */ | 362 | /* Take a reference on the file private data */ |
@@ -728,6 +728,10 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
728 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 728 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
729 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 729 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
730 | 730 | ||
731 | void cifs_oplock_break(struct work_struct *work); | ||
732 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | ||
733 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | ||
734 | |||
731 | extern const struct slow_work_ops cifs_oplock_break_ops; | 735 | extern const struct slow_work_ops cifs_oplock_break_ops; |
732 | 736 | ||
733 | #endif /* _CIFS_GLOB_H */ | 737 | #endif /* _CIFS_GLOB_H */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index a7de5e9fff11..578d88c5b46e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -157,7 +157,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
157 | mutex_init(&pCifsFile->lock_mutex); | 157 | mutex_init(&pCifsFile->lock_mutex); |
158 | INIT_LIST_HEAD(&pCifsFile->llist); | 158 | INIT_LIST_HEAD(&pCifsFile->llist); |
159 | atomic_set(&pCifsFile->count, 1); | 159 | atomic_set(&pCifsFile->count, 1); |
160 | slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); | 160 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); |
161 | 161 | ||
162 | write_lock(&GlobalSMBSeslock); | 162 | write_lock(&GlobalSMBSeslock); |
163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | 163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index fa04a00d126d..db11fdef0e92 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2307,8 +2307,7 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset) | |||
2307 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); | 2307 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); |
2308 | } | 2308 | } |
2309 | 2309 | ||
2310 | static void | 2310 | void cifs_oplock_break(struct work_struct *work) |
2311 | cifs_oplock_break(struct slow_work *work) | ||
2312 | { | 2311 | { |
2313 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 2312 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
2314 | oplock_break); | 2313 | oplock_break); |
@@ -2345,33 +2344,30 @@ cifs_oplock_break(struct slow_work *work) | |||
2345 | LOCKING_ANDX_OPLOCK_RELEASE, false); | 2344 | LOCKING_ANDX_OPLOCK_RELEASE, false); |
2346 | cFYI(1, "Oplock release rc = %d", rc); | 2345 | cFYI(1, "Oplock release rc = %d", rc); |
2347 | } | 2346 | } |
2347 | |||
2348 | /* | ||
2349 | * We might have kicked in before is_valid_oplock_break() | ||
2350 | * finished grabbing reference for us. Make sure it's done by | ||
2351 | * waiting for GlobalSMSSeslock. | ||
2352 | */ | ||
2353 | write_lock(&GlobalSMBSeslock); | ||
2354 | write_unlock(&GlobalSMBSeslock); | ||
2355 | |||
2356 | cifs_oplock_break_put(cfile); | ||
2348 | } | 2357 | } |
2349 | 2358 | ||
2350 | static int | 2359 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2351 | cifs_oplock_break_get(struct slow_work *work) | ||
2352 | { | 2360 | { |
2353 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2354 | oplock_break); | ||
2355 | mntget(cfile->mnt); | 2361 | mntget(cfile->mnt); |
2356 | cifsFileInfo_get(cfile); | 2362 | cifsFileInfo_get(cfile); |
2357 | return 0; | ||
2358 | } | 2363 | } |
2359 | 2364 | ||
2360 | static void | 2365 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
2361 | cifs_oplock_break_put(struct slow_work *work) | ||
2362 | { | 2366 | { |
2363 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2364 | oplock_break); | ||
2365 | mntput(cfile->mnt); | 2367 | mntput(cfile->mnt); |
2366 | cifsFileInfo_put(cfile); | 2368 | cifsFileInfo_put(cfile); |
2367 | } | 2369 | } |
2368 | 2370 | ||
2369 | const struct slow_work_ops cifs_oplock_break_ops = { | ||
2370 | .get_ref = cifs_oplock_break_get, | ||
2371 | .put_ref = cifs_oplock_break_put, | ||
2372 | .execute = cifs_oplock_break, | ||
2373 | }; | ||
2374 | |||
2375 | const struct address_space_operations cifs_addr_ops = { | 2371 | const struct address_space_operations cifs_addr_ops = { |
2376 | .readpage = cifs_readpage, | 2372 | .readpage = cifs_readpage, |
2377 | .readpages = cifs_readpages, | 2373 | .readpages = cifs_readpages, |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1394aa37f26c..3ccadc1326d6 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -498,7 +498,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
498 | struct cifsTconInfo *tcon; | 498 | struct cifsTconInfo *tcon; |
499 | struct cifsInodeInfo *pCifsInode; | 499 | struct cifsInodeInfo *pCifsInode; |
500 | struct cifsFileInfo *netfile; | 500 | struct cifsFileInfo *netfile; |
501 | int rc; | ||
502 | 501 | ||
503 | cFYI(1, "Checking for oplock break or dnotify response"); | 502 | cFYI(1, "Checking for oplock break or dnotify response"); |
504 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && | 503 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && |
@@ -583,13 +582,18 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
583 | pCifsInode->clientCanCacheAll = false; | 582 | pCifsInode->clientCanCacheAll = false; |
584 | if (pSMB->OplockLevel == 0) | 583 | if (pSMB->OplockLevel == 0) |
585 | pCifsInode->clientCanCacheRead = false; | 584 | pCifsInode->clientCanCacheRead = false; |
586 | rc = slow_work_enqueue(&netfile->oplock_break); | 585 | |
587 | if (rc) { | 586 | /* |
588 | cERROR(1, "failed to enqueue oplock " | 587 | * cifs_oplock_break_put() can't be called |
589 | "break: %d\n", rc); | 588 | * from here. Get reference after queueing |
590 | } else { | 589 | * succeeded. cifs_oplock_break() will |
591 | netfile->oplock_break_cancelled = false; | 590 | * synchronize using GlobalSMSSeslock. |
592 | } | 591 | */ |
592 | if (queue_work(system_nrt_wq, | ||
593 | &netfile->oplock_break)) | ||
594 | cifs_oplock_break_get(netfile); | ||
595 | netfile->oplock_break_cancelled = false; | ||
596 | |||
593 | read_unlock(&GlobalSMBSeslock); | 597 | read_unlock(&GlobalSMBSeslock); |
594 | read_unlock(&cifs_tcp_ses_lock); | 598 | read_unlock(&cifs_tcp_ses_lock); |
595 | return true; | 599 | return true; |
diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig index cc94bb9563f2..3f6dfa989881 100644 --- a/fs/fscache/Kconfig +++ b/fs/fscache/Kconfig | |||
@@ -1,7 +1,6 @@ | |||
1 | 1 | ||
2 | config FSCACHE | 2 | config FSCACHE |
3 | tristate "General filesystem local caching manager" | 3 | tristate "General filesystem local caching manager" |
4 | select SLOW_WORK | ||
5 | help | 4 | help |
6 | This option enables a generic filesystem caching manager that can be | 5 | This option enables a generic filesystem caching manager that can be |
7 | used by various network and other filesystems to cache data locally. | 6 | used by various network and other filesystems to cache data locally. |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index edd7434ab6e5..6a026441c5a6 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -82,6 +82,14 @@ extern unsigned fscache_defer_lookup; | |||
82 | extern unsigned fscache_defer_create; | 82 | extern unsigned fscache_defer_create; |
83 | extern unsigned fscache_debug; | 83 | extern unsigned fscache_debug; |
84 | extern struct kobject *fscache_root; | 84 | extern struct kobject *fscache_root; |
85 | extern struct workqueue_struct *fscache_object_wq; | ||
86 | extern struct workqueue_struct *fscache_op_wq; | ||
87 | DECLARE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); | ||
88 | |||
89 | static inline bool fscache_object_congested(void) | ||
90 | { | ||
91 | return workqueue_congested(WORK_CPU_UNBOUND, fscache_object_wq); | ||
92 | } | ||
85 | 93 | ||
86 | extern int fscache_wait_bit(void *); | 94 | extern int fscache_wait_bit(void *); |
87 | extern int fscache_wait_bit_interruptible(void *); | 95 | extern int fscache_wait_bit_interruptible(void *); |
diff --git a/fs/fscache/main.c b/fs/fscache/main.c index add6bdb53f04..f9d856773f79 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/completion.h> | 16 | #include <linux/completion.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/seq_file.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | MODULE_DESCRIPTION("FS Cache Manager"); | 21 | MODULE_DESCRIPTION("FS Cache Manager"); |
@@ -40,22 +41,105 @@ MODULE_PARM_DESC(fscache_debug, | |||
40 | "FS-Cache debugging mask"); | 41 | "FS-Cache debugging mask"); |
41 | 42 | ||
42 | struct kobject *fscache_root; | 43 | struct kobject *fscache_root; |
44 | struct workqueue_struct *fscache_object_wq; | ||
45 | struct workqueue_struct *fscache_op_wq; | ||
46 | |||
47 | DEFINE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); | ||
48 | |||
49 | /* these values serve as lower bounds, will be adjusted in fscache_init() */ | ||
50 | static unsigned fscache_object_max_active = 4; | ||
51 | static unsigned fscache_op_max_active = 2; | ||
52 | |||
53 | #ifdef CONFIG_SYSCTL | ||
54 | static struct ctl_table_header *fscache_sysctl_header; | ||
55 | |||
56 | static int fscache_max_active_sysctl(struct ctl_table *table, int write, | ||
57 | void __user *buffer, | ||
58 | size_t *lenp, loff_t *ppos) | ||
59 | { | ||
60 | struct workqueue_struct **wqp = table->extra1; | ||
61 | unsigned int *datap = table->data; | ||
62 | int ret; | ||
63 | |||
64 | ret = proc_dointvec(table, write, buffer, lenp, ppos); | ||
65 | if (ret == 0) | ||
66 | workqueue_set_max_active(*wqp, *datap); | ||
67 | return ret; | ||
68 | } | ||
69 | |||
70 | ctl_table fscache_sysctls[] = { | ||
71 | { | ||
72 | .procname = "object_max_active", | ||
73 | .data = &fscache_object_max_active, | ||
74 | .maxlen = sizeof(unsigned), | ||
75 | .mode = 0644, | ||
76 | .proc_handler = fscache_max_active_sysctl, | ||
77 | .extra1 = &fscache_object_wq, | ||
78 | }, | ||
79 | { | ||
80 | .procname = "operation_max_active", | ||
81 | .data = &fscache_op_max_active, | ||
82 | .maxlen = sizeof(unsigned), | ||
83 | .mode = 0644, | ||
84 | .proc_handler = fscache_max_active_sysctl, | ||
85 | .extra1 = &fscache_op_wq, | ||
86 | }, | ||
87 | {} | ||
88 | }; | ||
89 | |||
90 | ctl_table fscache_sysctls_root[] = { | ||
91 | { | ||
92 | .procname = "fscache", | ||
93 | .mode = 0555, | ||
94 | .child = fscache_sysctls, | ||
95 | }, | ||
96 | {} | ||
97 | }; | ||
98 | #endif | ||
43 | 99 | ||
44 | /* | 100 | /* |
45 | * initialise the fs caching module | 101 | * initialise the fs caching module |
46 | */ | 102 | */ |
47 | static int __init fscache_init(void) | 103 | static int __init fscache_init(void) |
48 | { | 104 | { |
105 | unsigned int nr_cpus = num_possible_cpus(); | ||
106 | unsigned int cpu; | ||
49 | int ret; | 107 | int ret; |
50 | 108 | ||
51 | ret = slow_work_register_user(THIS_MODULE); | 109 | fscache_object_max_active = |
52 | if (ret < 0) | 110 | clamp_val(nr_cpus, |
53 | goto error_slow_work; | 111 | fscache_object_max_active, WQ_UNBOUND_MAX_ACTIVE); |
112 | |||
113 | ret = -ENOMEM; | ||
114 | fscache_object_wq = alloc_workqueue("fscache_object", WQ_UNBOUND, | ||
115 | fscache_object_max_active); | ||
116 | if (!fscache_object_wq) | ||
117 | goto error_object_wq; | ||
118 | |||
119 | fscache_op_max_active = | ||
120 | clamp_val(fscache_object_max_active / 2, | ||
121 | fscache_op_max_active, WQ_UNBOUND_MAX_ACTIVE); | ||
122 | |||
123 | ret = -ENOMEM; | ||
124 | fscache_op_wq = alloc_workqueue("fscache_operation", WQ_UNBOUND, | ||
125 | fscache_op_max_active); | ||
126 | if (!fscache_op_wq) | ||
127 | goto error_op_wq; | ||
128 | |||
129 | for_each_possible_cpu(cpu) | ||
130 | init_waitqueue_head(&per_cpu(fscache_object_cong_wait, cpu)); | ||
54 | 131 | ||
55 | ret = fscache_proc_init(); | 132 | ret = fscache_proc_init(); |
56 | if (ret < 0) | 133 | if (ret < 0) |
57 | goto error_proc; | 134 | goto error_proc; |
58 | 135 | ||
136 | #ifdef CONFIG_SYSCTL | ||
137 | ret = -ENOMEM; | ||
138 | fscache_sysctl_header = register_sysctl_table(fscache_sysctls_root); | ||
139 | if (!fscache_sysctl_header) | ||
140 | goto error_sysctl; | ||
141 | #endif | ||
142 | |||
59 | fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", | 143 | fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", |
60 | sizeof(struct fscache_cookie), | 144 | sizeof(struct fscache_cookie), |
61 | 0, | 145 | 0, |
@@ -78,10 +162,16 @@ static int __init fscache_init(void) | |||
78 | error_kobj: | 162 | error_kobj: |
79 | kmem_cache_destroy(fscache_cookie_jar); | 163 | kmem_cache_destroy(fscache_cookie_jar); |
80 | error_cookie_jar: | 164 | error_cookie_jar: |
165 | #ifdef CONFIG_SYSCTL | ||
166 | unregister_sysctl_table(fscache_sysctl_header); | ||
167 | error_sysctl: | ||
168 | #endif | ||
81 | fscache_proc_cleanup(); | 169 | fscache_proc_cleanup(); |
82 | error_proc: | 170 | error_proc: |
83 | slow_work_unregister_user(THIS_MODULE); | 171 | destroy_workqueue(fscache_op_wq); |
84 | error_slow_work: | 172 | error_op_wq: |
173 | destroy_workqueue(fscache_object_wq); | ||
174 | error_object_wq: | ||
85 | return ret; | 175 | return ret; |
86 | } | 176 | } |
87 | 177 | ||
@@ -96,8 +186,12 @@ static void __exit fscache_exit(void) | |||
96 | 186 | ||
97 | kobject_put(fscache_root); | 187 | kobject_put(fscache_root); |
98 | kmem_cache_destroy(fscache_cookie_jar); | 188 | kmem_cache_destroy(fscache_cookie_jar); |
189 | #ifdef CONFIG_SYSCTL | ||
190 | unregister_sysctl_table(fscache_sysctl_header); | ||
191 | #endif | ||
99 | fscache_proc_cleanup(); | 192 | fscache_proc_cleanup(); |
100 | slow_work_unregister_user(THIS_MODULE); | 193 | destroy_workqueue(fscache_op_wq); |
194 | destroy_workqueue(fscache_object_wq); | ||
101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); | 195 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); |
102 | } | 196 | } |
103 | 197 | ||
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index 4a8eb31c5338..ebe29c581380 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -34,8 +34,8 @@ struct fscache_objlist_data { | |||
34 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ | 34 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ |
35 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ | 35 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ |
36 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ | 36 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ |
37 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */ | 37 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with work */ |
38 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */ | 38 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without work */ |
39 | 39 | ||
40 | u8 buf[512]; /* key and aux data buffer */ | 40 | u8 buf[512]; /* key and aux data buffer */ |
41 | }; | 41 | }; |
@@ -231,12 +231,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
231 | READS, NOREADS); | 231 | READS, NOREADS); |
232 | FILTER(obj->events & obj->event_mask, | 232 | FILTER(obj->events & obj->event_mask, |
233 | EVENTS, NOEVENTS); | 233 | EVENTS, NOEVENTS); |
234 | FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW), | 234 | FILTER(work_busy(&obj->work), WORK, NOWORK); |
235 | WORK, NOWORK); | ||
236 | } | 235 | } |
237 | 236 | ||
238 | seq_printf(m, | 237 | seq_printf(m, |
239 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ", | 238 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ", |
240 | obj->debug_id, | 239 | obj->debug_id, |
241 | obj->parent ? obj->parent->debug_id : -1, | 240 | obj->parent ? obj->parent->debug_id : -1, |
242 | fscache_object_states_short[obj->state], | 241 | fscache_object_states_short[obj->state], |
@@ -249,7 +248,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
249 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | 248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, |
250 | obj->events, | 249 | obj->events, |
251 | obj->flags, | 250 | obj->flags, |
252 | obj->work.flags); | 251 | work_busy(&obj->work)); |
253 | 252 | ||
254 | no_cookie = true; | 253 | no_cookie = true; |
255 | keylen = auxlen = 0; | 254 | keylen = auxlen = 0; |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 0b589a9b4ffc..b6b897c550ac 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/seq_file.h> | ||
18 | #include "internal.h" | 17 | #include "internal.h" |
19 | 18 | ||
20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 19 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
@@ -50,12 +49,8 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | |||
50 | [FSCACHE_OBJECT_DEAD] = "DEAD", | 49 | [FSCACHE_OBJECT_DEAD] = "DEAD", |
51 | }; | 50 | }; |
52 | 51 | ||
53 | static void fscache_object_slow_work_put_ref(struct slow_work *); | 52 | static int fscache_get_object(struct fscache_object *); |
54 | static int fscache_object_slow_work_get_ref(struct slow_work *); | 53 | static void fscache_put_object(struct fscache_object *); |
55 | static void fscache_object_slow_work_execute(struct slow_work *); | ||
56 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
57 | static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); | ||
58 | #endif | ||
59 | static void fscache_initialise_object(struct fscache_object *); | 54 | static void fscache_initialise_object(struct fscache_object *); |
60 | static void fscache_lookup_object(struct fscache_object *); | 55 | static void fscache_lookup_object(struct fscache_object *); |
61 | static void fscache_object_available(struct fscache_object *); | 56 | static void fscache_object_available(struct fscache_object *); |
@@ -64,17 +59,6 @@ static void fscache_withdraw_object(struct fscache_object *); | |||
64 | static void fscache_enqueue_dependents(struct fscache_object *); | 59 | static void fscache_enqueue_dependents(struct fscache_object *); |
65 | static void fscache_dequeue_object(struct fscache_object *); | 60 | static void fscache_dequeue_object(struct fscache_object *); |
66 | 61 | ||
67 | const struct slow_work_ops fscache_object_slow_work_ops = { | ||
68 | .owner = THIS_MODULE, | ||
69 | .get_ref = fscache_object_slow_work_get_ref, | ||
70 | .put_ref = fscache_object_slow_work_put_ref, | ||
71 | .execute = fscache_object_slow_work_execute, | ||
72 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
73 | .desc = fscache_object_slow_work_desc, | ||
74 | #endif | ||
75 | }; | ||
76 | EXPORT_SYMBOL(fscache_object_slow_work_ops); | ||
77 | |||
78 | /* | 62 | /* |
79 | * we need to notify the parent when an op completes that we had outstanding | 63 | * we need to notify the parent when an op completes that we had outstanding |
80 | * upon it | 64 | * upon it |
@@ -345,7 +329,7 @@ unsupported_event: | |||
345 | /* | 329 | /* |
346 | * execute an object | 330 | * execute an object |
347 | */ | 331 | */ |
348 | static void fscache_object_slow_work_execute(struct slow_work *work) | 332 | void fscache_object_work_func(struct work_struct *work) |
349 | { | 333 | { |
350 | struct fscache_object *object = | 334 | struct fscache_object *object = |
351 | container_of(work, struct fscache_object, work); | 335 | container_of(work, struct fscache_object, work); |
@@ -359,23 +343,9 @@ static void fscache_object_slow_work_execute(struct slow_work *work) | |||
359 | if (object->events & object->event_mask) | 343 | if (object->events & object->event_mask) |
360 | fscache_enqueue_object(object); | 344 | fscache_enqueue_object(object); |
361 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | 345 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); |
346 | fscache_put_object(object); | ||
362 | } | 347 | } |
363 | 348 | EXPORT_SYMBOL(fscache_object_work_func); | |
364 | /* | ||
365 | * describe an object for slow-work debugging | ||
366 | */ | ||
367 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
368 | static void fscache_object_slow_work_desc(struct slow_work *work, | ||
369 | struct seq_file *m) | ||
370 | { | ||
371 | struct fscache_object *object = | ||
372 | container_of(work, struct fscache_object, work); | ||
373 | |||
374 | seq_printf(m, "FSC: OBJ%x: %s", | ||
375 | object->debug_id, | ||
376 | fscache_object_states_short[object->state]); | ||
377 | } | ||
378 | #endif | ||
379 | 349 | ||
380 | /* | 350 | /* |
381 | * initialise an object | 351 | * initialise an object |
@@ -393,7 +363,6 @@ static void fscache_initialise_object(struct fscache_object *object) | |||
393 | _enter(""); | 363 | _enter(""); |
394 | ASSERT(object->cookie != NULL); | 364 | ASSERT(object->cookie != NULL); |
395 | ASSERT(object->cookie->parent != NULL); | 365 | ASSERT(object->cookie->parent != NULL); |
396 | ASSERT(list_empty(&object->work.link)); | ||
397 | 366 | ||
398 | if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | | 367 | if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | |
399 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | 368 | (1 << FSCACHE_OBJECT_EV_RELEASE) | |
@@ -671,10 +640,8 @@ static void fscache_drop_object(struct fscache_object *object) | |||
671 | object->parent = NULL; | 640 | object->parent = NULL; |
672 | } | 641 | } |
673 | 642 | ||
674 | /* this just shifts the object release to the slow work processor */ | 643 | /* this just shifts the object release to the work processor */ |
675 | fscache_stat(&fscache_n_cop_put_object); | 644 | fscache_put_object(object); |
676 | object->cache->ops->put_object(object); | ||
677 | fscache_stat_d(&fscache_n_cop_put_object); | ||
678 | 645 | ||
679 | _leave(""); | 646 | _leave(""); |
680 | } | 647 | } |
@@ -758,12 +725,10 @@ void fscache_withdrawing_object(struct fscache_cache *cache, | |||
758 | } | 725 | } |
759 | 726 | ||
760 | /* | 727 | /* |
761 | * allow the slow work item processor to get a ref on an object | 728 | * get a ref on an object |
762 | */ | 729 | */ |
763 | static int fscache_object_slow_work_get_ref(struct slow_work *work) | 730 | static int fscache_get_object(struct fscache_object *object) |
764 | { | 731 | { |
765 | struct fscache_object *object = | ||
766 | container_of(work, struct fscache_object, work); | ||
767 | int ret; | 732 | int ret; |
768 | 733 | ||
769 | fscache_stat(&fscache_n_cop_grab_object); | 734 | fscache_stat(&fscache_n_cop_grab_object); |
@@ -773,13 +738,10 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work) | |||
773 | } | 738 | } |
774 | 739 | ||
775 | /* | 740 | /* |
776 | * allow the slow work item processor to discard a ref on a work item | 741 | * discard a ref on a work item |
777 | */ | 742 | */ |
778 | static void fscache_object_slow_work_put_ref(struct slow_work *work) | 743 | static void fscache_put_object(struct fscache_object *object) |
779 | { | 744 | { |
780 | struct fscache_object *object = | ||
781 | container_of(work, struct fscache_object, work); | ||
782 | |||
783 | fscache_stat(&fscache_n_cop_put_object); | 745 | fscache_stat(&fscache_n_cop_put_object); |
784 | object->cache->ops->put_object(object); | 746 | object->cache->ops->put_object(object); |
785 | fscache_stat_d(&fscache_n_cop_put_object); | 747 | fscache_stat_d(&fscache_n_cop_put_object); |
@@ -792,8 +754,48 @@ void fscache_enqueue_object(struct fscache_object *object) | |||
792 | { | 754 | { |
793 | _enter("{OBJ%x}", object->debug_id); | 755 | _enter("{OBJ%x}", object->debug_id); |
794 | 756 | ||
795 | slow_work_enqueue(&object->work); | 757 | if (fscache_get_object(object) >= 0) { |
758 | wait_queue_head_t *cong_wq = | ||
759 | &get_cpu_var(fscache_object_cong_wait); | ||
760 | |||
761 | if (queue_work(fscache_object_wq, &object->work)) { | ||
762 | if (fscache_object_congested()) | ||
763 | wake_up(cong_wq); | ||
764 | } else | ||
765 | fscache_put_object(object); | ||
766 | |||
767 | put_cpu_var(fscache_object_cong_wait); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /** | ||
772 | * fscache_object_sleep_till_congested - Sleep until object wq is congested | ||
773 | * @timoutp: Scheduler sleep timeout | ||
774 | * | ||
775 | * Allow an object handler to sleep until the object workqueue is congested. | ||
776 | * | ||
777 | * The caller must set up a wake up event before calling this and must have set | ||
778 | * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own | ||
779 | * condition before calling this function as no test is made here. | ||
780 | * | ||
781 | * %true is returned if the object wq is congested, %false otherwise. | ||
782 | */ | ||
783 | bool fscache_object_sleep_till_congested(signed long *timeoutp) | ||
784 | { | ||
785 | wait_queue_head_t *cong_wq = &__get_cpu_var(fscache_object_cong_wait); | ||
786 | DEFINE_WAIT(wait); | ||
787 | |||
788 | if (fscache_object_congested()) | ||
789 | return true; | ||
790 | |||
791 | add_wait_queue_exclusive(cong_wq, &wait); | ||
792 | if (!fscache_object_congested()) | ||
793 | *timeoutp = schedule_timeout(*timeoutp); | ||
794 | finish_wait(cong_wq, &wait); | ||
795 | |||
796 | return fscache_object_congested(); | ||
796 | } | 797 | } |
798 | EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested); | ||
797 | 799 | ||
798 | /* | 800 | /* |
799 | * enqueue the dependents of an object for metadata-type processing | 801 | * enqueue the dependents of an object for metadata-type processing |
@@ -819,9 +821,7 @@ static void fscache_enqueue_dependents(struct fscache_object *object) | |||
819 | 821 | ||
820 | /* sort onto appropriate lists */ | 822 | /* sort onto appropriate lists */ |
821 | fscache_enqueue_object(dep); | 823 | fscache_enqueue_object(dep); |
822 | fscache_stat(&fscache_n_cop_put_object); | 824 | fscache_put_object(dep); |
823 | dep->cache->ops->put_object(dep); | ||
824 | fscache_stat_d(&fscache_n_cop_put_object); | ||
825 | 825 | ||
826 | if (!list_empty(&object->dependents)) | 826 | if (!list_empty(&object->dependents)) |
827 | cond_resched_lock(&object->lock); | 827 | cond_resched_lock(&object->lock); |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index f17cecafae44..b9f34eaede09 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -42,16 +42,12 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
42 | 42 | ||
43 | fscache_stat(&fscache_n_op_enqueue); | 43 | fscache_stat(&fscache_n_op_enqueue); |
44 | switch (op->flags & FSCACHE_OP_TYPE) { | 44 | switch (op->flags & FSCACHE_OP_TYPE) { |
45 | case FSCACHE_OP_FAST: | 45 | case FSCACHE_OP_ASYNC: |
46 | _debug("queue fast"); | 46 | _debug("queue async"); |
47 | atomic_inc(&op->usage); | 47 | atomic_inc(&op->usage); |
48 | if (!schedule_work(&op->fast_work)) | 48 | if (!queue_work(fscache_op_wq, &op->work)) |
49 | fscache_put_operation(op); | 49 | fscache_put_operation(op); |
50 | break; | 50 | break; |
51 | case FSCACHE_OP_SLOW: | ||
52 | _debug("queue slow"); | ||
53 | slow_work_enqueue(&op->slow_work); | ||
54 | break; | ||
55 | case FSCACHE_OP_MYTHREAD: | 51 | case FSCACHE_OP_MYTHREAD: |
56 | _debug("queue for caller's attention"); | 52 | _debug("queue for caller's attention"); |
57 | break; | 53 | break; |
@@ -455,36 +451,13 @@ void fscache_operation_gc(struct work_struct *work) | |||
455 | } | 451 | } |
456 | 452 | ||
457 | /* | 453 | /* |
458 | * allow the slow work item processor to get a ref on an operation | 454 | * execute an operation using fs_op_wq to provide processing context - |
459 | */ | 455 | * the caller holds a ref to this object, so we don't need to hold one |
460 | static int fscache_op_get_ref(struct slow_work *work) | ||
461 | { | ||
462 | struct fscache_operation *op = | ||
463 | container_of(work, struct fscache_operation, slow_work); | ||
464 | |||
465 | atomic_inc(&op->usage); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | /* | ||
470 | * allow the slow work item processor to discard a ref on an operation | ||
471 | */ | ||
472 | static void fscache_op_put_ref(struct slow_work *work) | ||
473 | { | ||
474 | struct fscache_operation *op = | ||
475 | container_of(work, struct fscache_operation, slow_work); | ||
476 | |||
477 | fscache_put_operation(op); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * execute an operation using the slow thread pool to provide processing context | ||
482 | * - the caller holds a ref to this object, so we don't need to hold one | ||
483 | */ | 456 | */ |
484 | static void fscache_op_execute(struct slow_work *work) | 457 | void fscache_op_work_func(struct work_struct *work) |
485 | { | 458 | { |
486 | struct fscache_operation *op = | 459 | struct fscache_operation *op = |
487 | container_of(work, struct fscache_operation, slow_work); | 460 | container_of(work, struct fscache_operation, work); |
488 | unsigned long start; | 461 | unsigned long start; |
489 | 462 | ||
490 | _enter("{OBJ%x OP%x,%d}", | 463 | _enter("{OBJ%x OP%x,%d}", |
@@ -494,31 +467,7 @@ static void fscache_op_execute(struct slow_work *work) | |||
494 | start = jiffies; | 467 | start = jiffies; |
495 | op->processor(op); | 468 | op->processor(op); |
496 | fscache_hist(fscache_ops_histogram, start); | 469 | fscache_hist(fscache_ops_histogram, start); |
470 | fscache_put_operation(op); | ||
497 | 471 | ||
498 | _leave(""); | 472 | _leave(""); |
499 | } | 473 | } |
500 | |||
501 | /* | ||
502 | * describe an operation for slow-work debugging | ||
503 | */ | ||
504 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
505 | static void fscache_op_desc(struct slow_work *work, struct seq_file *m) | ||
506 | { | ||
507 | struct fscache_operation *op = | ||
508 | container_of(work, struct fscache_operation, slow_work); | ||
509 | |||
510 | seq_printf(m, "FSC: OBJ%x OP%x: %s/%s fl=%lx", | ||
511 | op->object->debug_id, op->debug_id, | ||
512 | op->name, op->state, op->flags); | ||
513 | } | ||
514 | #endif | ||
515 | |||
516 | const struct slow_work_ops fscache_op_slow_work_ops = { | ||
517 | .owner = THIS_MODULE, | ||
518 | .get_ref = fscache_op_get_ref, | ||
519 | .put_ref = fscache_op_put_ref, | ||
520 | .execute = fscache_op_execute, | ||
521 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
522 | .desc = fscache_op_desc, | ||
523 | #endif | ||
524 | }; | ||
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 723b889fd219..41c441c2058d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -105,7 +105,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | |||
105 | 105 | ||
106 | page_busy: | 106 | page_busy: |
107 | /* we might want to wait here, but that could deadlock the allocator as | 107 | /* we might want to wait here, but that could deadlock the allocator as |
108 | * the slow-work threads writing to the cache may all end up sleeping | 108 | * the work threads writing to the cache may all end up sleeping |
109 | * on memory allocation */ | 109 | * on memory allocation */ |
110 | fscache_stat(&fscache_n_store_vmscan_busy); | 110 | fscache_stat(&fscache_n_store_vmscan_busy); |
111 | return false; | 111 | return false; |
@@ -188,9 +188,8 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
188 | return -ENOMEM; | 188 | return -ENOMEM; |
189 | } | 189 | } |
190 | 190 | ||
191 | fscache_operation_init(op, NULL); | 191 | fscache_operation_init(op, fscache_attr_changed_op, NULL); |
192 | fscache_operation_init_slow(op, fscache_attr_changed_op); | 192 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); |
193 | op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE); | ||
194 | fscache_set_op_name(op, "Attr"); | 193 | fscache_set_op_name(op, "Attr"); |
195 | 194 | ||
196 | spin_lock(&cookie->lock); | 195 | spin_lock(&cookie->lock); |
@@ -218,24 +217,6 @@ nobufs: | |||
218 | EXPORT_SYMBOL(__fscache_attr_changed); | 217 | EXPORT_SYMBOL(__fscache_attr_changed); |
219 | 218 | ||
220 | /* | 219 | /* |
221 | * handle secondary execution given to a retrieval op on behalf of the | ||
222 | * cache | ||
223 | */ | ||
224 | static void fscache_retrieval_work(struct work_struct *work) | ||
225 | { | ||
226 | struct fscache_retrieval *op = | ||
227 | container_of(work, struct fscache_retrieval, op.fast_work); | ||
228 | unsigned long start; | ||
229 | |||
230 | _enter("{OP%x}", op->op.debug_id); | ||
231 | |||
232 | start = jiffies; | ||
233 | op->op.processor(&op->op); | ||
234 | fscache_hist(fscache_ops_histogram, start); | ||
235 | fscache_put_operation(&op->op); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * release a retrieval op reference | 220 | * release a retrieval op reference |
240 | */ | 221 | */ |
241 | static void fscache_release_retrieval_op(struct fscache_operation *_op) | 222 | static void fscache_release_retrieval_op(struct fscache_operation *_op) |
@@ -269,13 +250,12 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
269 | return NULL; | 250 | return NULL; |
270 | } | 251 | } |
271 | 252 | ||
272 | fscache_operation_init(&op->op, fscache_release_retrieval_op); | 253 | fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); |
273 | op->op.flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING); | 254 | op->op.flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING); |
274 | op->mapping = mapping; | 255 | op->mapping = mapping; |
275 | op->end_io_func = end_io_func; | 256 | op->end_io_func = end_io_func; |
276 | op->context = context; | 257 | op->context = context; |
277 | op->start_time = jiffies; | 258 | op->start_time = jiffies; |
278 | INIT_WORK(&op->op.fast_work, fscache_retrieval_work); | ||
279 | INIT_LIST_HEAD(&op->to_do); | 259 | INIT_LIST_HEAD(&op->to_do); |
280 | fscache_set_op_name(&op->op, "Retr"); | 260 | fscache_set_op_name(&op->op, "Retr"); |
281 | return op; | 261 | return op; |
@@ -795,9 +775,9 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
795 | if (!op) | 775 | if (!op) |
796 | goto nomem; | 776 | goto nomem; |
797 | 777 | ||
798 | fscache_operation_init(&op->op, fscache_release_write_op); | 778 | fscache_operation_init(&op->op, fscache_write_op, |
799 | fscache_operation_init_slow(&op->op, fscache_write_op); | 779 | fscache_release_write_op); |
800 | op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING); | 780 | op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING); |
801 | fscache_set_op_name(&op->op, "Write1"); | 781 | fscache_set_op_name(&op->op, "Write1"); |
802 | 782 | ||
803 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); | 783 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); |
@@ -852,7 +832,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
852 | fscache_stat(&fscache_n_store_ops); | 832 | fscache_stat(&fscache_n_store_ops); |
853 | fscache_stat(&fscache_n_stores_ok); | 833 | fscache_stat(&fscache_n_stores_ok); |
854 | 834 | ||
855 | /* the slow work queue now carries its own ref on the object */ | 835 | /* the work queue now carries its own ref on the object */ |
856 | fscache_put_operation(&op->op); | 836 | fscache_put_operation(&op->op); |
857 | _leave(" = 0"); | 837 | _leave(" = 0"); |
858 | return 0; | 838 | return 0; |
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index a47b43107112..cc9665522148 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -7,7 +7,6 @@ config GFS2_FS | |||
7 | select IP_SCTP if DLM_SCTP | 7 | select IP_SCTP if DLM_SCTP |
8 | select FS_POSIX_ACL | 8 | select FS_POSIX_ACL |
9 | select CRC32 | 9 | select CRC32 |
10 | select SLOW_WORK | ||
11 | select QUOTACTL | 10 | select QUOTACTL |
12 | help | 11 | help |
13 | A cluster filesystem. | 12 | A cluster filesystem. |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8fcbce48a128..fdbf4b366fa5 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -12,7 +12,6 @@ | |||
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/workqueue.h> | 14 | #include <linux/workqueue.h> |
15 | #include <linux/slow-work.h> | ||
16 | #include <linux/dlm.h> | 15 | #include <linux/dlm.h> |
17 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
18 | 17 | ||
@@ -383,7 +382,7 @@ struct gfs2_journal_extent { | |||
383 | struct gfs2_jdesc { | 382 | struct gfs2_jdesc { |
384 | struct list_head jd_list; | 383 | struct list_head jd_list; |
385 | struct list_head extent_list; | 384 | struct list_head extent_list; |
386 | struct slow_work jd_work; | 385 | struct work_struct jd_work; |
387 | struct inode *jd_inode; | 386 | struct inode *jd_inode; |
388 | unsigned long jd_flags; | 387 | unsigned long jd_flags; |
389 | #define JDF_RECOVERY 1 | 388 | #define JDF_RECOVERY 1 |
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index fb2a5f93b7c3..b1e9630eb46a 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/gfs2_ondisk.h> | 16 | #include <linux/gfs2_ondisk.h> |
17 | #include <asm/atomic.h> | 17 | #include <asm/atomic.h> |
18 | #include <linux/slow-work.h> | ||
19 | 18 | ||
20 | #include "gfs2.h" | 19 | #include "gfs2.h" |
21 | #include "incore.h" | 20 | #include "incore.h" |
@@ -24,6 +23,7 @@ | |||
24 | #include "util.h" | 23 | #include "util.h" |
25 | #include "glock.h" | 24 | #include "glock.h" |
26 | #include "quota.h" | 25 | #include "quota.h" |
26 | #include "recovery.h" | ||
27 | 27 | ||
28 | static struct shrinker qd_shrinker = { | 28 | static struct shrinker qd_shrinker = { |
29 | .shrink = gfs2_shrink_qd_memory, | 29 | .shrink = gfs2_shrink_qd_memory, |
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void) | |||
138 | if (error) | 138 | if (error) |
139 | goto fail_unregister; | 139 | goto fail_unregister; |
140 | 140 | ||
141 | error = slow_work_register_user(THIS_MODULE); | 141 | error = -ENOMEM; |
142 | if (error) | 142 | gfs_recovery_wq = alloc_workqueue("gfs_recovery", |
143 | goto fail_slow; | 143 | WQ_NON_REENTRANT | WQ_RESCUER, 0); |
144 | if (!gfs_recovery_wq) | ||
145 | goto fail_wq; | ||
144 | 146 | ||
145 | gfs2_register_debugfs(); | 147 | gfs2_register_debugfs(); |
146 | 148 | ||
@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void) | |||
148 | 150 | ||
149 | return 0; | 151 | return 0; |
150 | 152 | ||
151 | fail_slow: | 153 | fail_wq: |
152 | unregister_filesystem(&gfs2meta_fs_type); | 154 | unregister_filesystem(&gfs2meta_fs_type); |
153 | fail_unregister: | 155 | fail_unregister: |
154 | unregister_filesystem(&gfs2_fs_type); | 156 | unregister_filesystem(&gfs2_fs_type); |
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void) | |||
190 | gfs2_unregister_debugfs(); | 192 | gfs2_unregister_debugfs(); |
191 | unregister_filesystem(&gfs2_fs_type); | 193 | unregister_filesystem(&gfs2_fs_type); |
192 | unregister_filesystem(&gfs2meta_fs_type); | 194 | unregister_filesystem(&gfs2meta_fs_type); |
193 | slow_work_unregister_user(THIS_MODULE); | 195 | destroy_workqueue(gfs_recovery_wq); |
194 | 196 | ||
195 | kmem_cache_destroy(gfs2_quotad_cachep); | 197 | kmem_cache_destroy(gfs2_quotad_cachep); |
196 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 198 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 45a4a36195d8..4f44bdeb2f03 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
20 | #include <linux/slow-work.h> | ||
21 | #include <linux/quotaops.h> | 20 | #include <linux/quotaops.h> |
22 | 21 | ||
23 | #include "gfs2.h" | 22 | #include "gfs2.h" |
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) | |||
673 | break; | 672 | break; |
674 | 673 | ||
675 | INIT_LIST_HEAD(&jd->extent_list); | 674 | INIT_LIST_HEAD(&jd->extent_list); |
676 | slow_work_init(&jd->jd_work, &gfs2_recover_ops); | 675 | INIT_WORK(&jd->jd_work, gfs2_recover_func); |
677 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); | 676 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); |
678 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { | 677 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { |
679 | if (!jd->jd_inode) | 678 | if (!jd->jd_inode) |
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
782 | if (sdp->sd_lockstruct.ls_first) { | 781 | if (sdp->sd_lockstruct.ls_first) { |
783 | unsigned int x; | 782 | unsigned int x; |
784 | for (x = 0; x < sdp->sd_journals; x++) { | 783 | for (x = 0; x < sdp->sd_journals; x++) { |
785 | error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x)); | 784 | error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x), |
785 | true); | ||
786 | if (error) { | 786 | if (error) { |
787 | fs_err(sdp, "error recovering journal %u: %d\n", | 787 | fs_err(sdp, "error recovering journal %u: %d\n", |
788 | x, error); | 788 | x, error); |
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) | |||
792 | 792 | ||
793 | gfs2_others_may_mount(sdp); | 793 | gfs2_others_may_mount(sdp); |
794 | } else if (!sdp->sd_args.ar_spectator) { | 794 | } else if (!sdp->sd_args.ar_spectator) { |
795 | error = gfs2_recover_journal(sdp->sd_jdesc); | 795 | error = gfs2_recover_journal(sdp->sd_jdesc, true); |
796 | if (error) { | 796 | if (error) { |
797 | fs_err(sdp, "error recovering my journal: %d\n", error); | 797 | fs_err(sdp, "error recovering my journal: %d\n", error); |
798 | goto fail_jinode_gh; | 798 | goto fail_jinode_gh; |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 4b9bece3d437..f7f89a94a5a4 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/gfs2_ondisk.h> | 15 | #include <linux/gfs2_ondisk.h> |
16 | #include <linux/crc32.h> | 16 | #include <linux/crc32.h> |
17 | #include <linux/slow-work.h> | ||
18 | 17 | ||
19 | #include "gfs2.h" | 18 | #include "gfs2.h" |
20 | #include "incore.h" | 19 | #include "incore.h" |
@@ -28,6 +27,8 @@ | |||
28 | #include "util.h" | 27 | #include "util.h" |
29 | #include "dir.h" | 28 | #include "dir.h" |
30 | 29 | ||
30 | struct workqueue_struct *gfs_recovery_wq; | ||
31 | |||
31 | int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, | 32 | int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, |
32 | struct buffer_head **bh) | 33 | struct buffer_head **bh) |
33 | { | 34 | { |
@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, | |||
443 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); | 444 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); |
444 | } | 445 | } |
445 | 446 | ||
446 | static int gfs2_recover_get_ref(struct slow_work *work) | 447 | void gfs2_recover_func(struct work_struct *work) |
447 | { | ||
448 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
449 | if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags)) | ||
450 | return -EBUSY; | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static void gfs2_recover_put_ref(struct slow_work *work) | ||
455 | { | ||
456 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | ||
457 | clear_bit(JDF_RECOVERY, &jd->jd_flags); | ||
458 | smp_mb__after_clear_bit(); | ||
459 | wake_up_bit(&jd->jd_flags, JDF_RECOVERY); | ||
460 | } | ||
461 | |||
462 | static void gfs2_recover_work(struct slow_work *work) | ||
463 | { | 448 | { |
464 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); | 449 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); |
465 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); | 450 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work) | |||
578 | gfs2_glock_dq_uninit(&j_gh); | 563 | gfs2_glock_dq_uninit(&j_gh); |
579 | 564 | ||
580 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); | 565 | fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); |
581 | return; | 566 | goto done; |
582 | 567 | ||
583 | fail_gunlock_tr: | 568 | fail_gunlock_tr: |
584 | gfs2_glock_dq_uninit(&t_gh); | 569 | gfs2_glock_dq_uninit(&t_gh); |
@@ -590,32 +575,35 @@ fail_gunlock_j: | |||
590 | } | 575 | } |
591 | 576 | ||
592 | fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); | 577 | fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); |
593 | |||
594 | fail: | 578 | fail: |
595 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); | 579 | gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); |
580 | done: | ||
581 | clear_bit(JDF_RECOVERY, &jd->jd_flags); | ||
582 | smp_mb__after_clear_bit(); | ||
583 | wake_up_bit(&jd->jd_flags, JDF_RECOVERY); | ||
596 | } | 584 | } |
597 | 585 | ||
598 | struct slow_work_ops gfs2_recover_ops = { | ||
599 | .owner = THIS_MODULE, | ||
600 | .get_ref = gfs2_recover_get_ref, | ||
601 | .put_ref = gfs2_recover_put_ref, | ||
602 | .execute = gfs2_recover_work, | ||
603 | }; | ||
604 | |||
605 | |||
606 | static int gfs2_recovery_wait(void *word) | 586 | static int gfs2_recovery_wait(void *word) |
607 | { | 587 | { |
608 | schedule(); | 588 | schedule(); |
609 | return 0; | 589 | return 0; |
610 | } | 590 | } |
611 | 591 | ||
612 | int gfs2_recover_journal(struct gfs2_jdesc *jd) | 592 | int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait) |
613 | { | 593 | { |
614 | int rv; | 594 | int rv; |
615 | rv = slow_work_enqueue(&jd->jd_work); | 595 | |
616 | if (rv) | 596 | if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags)) |
617 | return rv; | 597 | return -EBUSY; |
618 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE); | 598 | |
599 | /* we have JDF_RECOVERY, queue should always succeed */ | ||
600 | rv = queue_work(gfs_recovery_wq, &jd->jd_work); | ||
601 | BUG_ON(!rv); | ||
602 | |||
603 | if (wait) | ||
604 | wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, | ||
605 | TASK_UNINTERRUPTIBLE); | ||
606 | |||
619 | return 0; | 607 | return 0; |
620 | } | 608 | } |
621 | 609 | ||
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 1616ac22569a..2226136c7647 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h | |||
@@ -12,6 +12,8 @@ | |||
12 | 12 | ||
13 | #include "incore.h" | 13 | #include "incore.h" |
14 | 14 | ||
15 | extern struct workqueue_struct *gfs_recovery_wq; | ||
16 | |||
15 | static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) | 17 | static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) |
16 | { | 18 | { |
17 | if (++*blk == sdp->sd_jdesc->jd_blocks) | 19 | if (++*blk == sdp->sd_jdesc->jd_blocks) |
@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); | |||
27 | 29 | ||
28 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, | 30 | extern int gfs2_find_jhead(struct gfs2_jdesc *jd, |
29 | struct gfs2_log_header_host *head); | 31 | struct gfs2_log_header_host *head); |
30 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); | 32 | extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait); |
31 | extern struct slow_work_ops gfs2_recover_ops; | 33 | extern void gfs2_recover_func(struct work_struct *work); |
32 | 34 | ||
33 | #endif /* __RECOVERY_DOT_H__ */ | 35 | #endif /* __RECOVERY_DOT_H__ */ |
34 | 36 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index d019d0d55e00..ccacffd2faaa 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "quota.h" | 25 | #include "quota.h" |
26 | #include "util.h" | 26 | #include "util.h" |
27 | #include "glops.h" | 27 | #include "glops.h" |
28 | #include "recovery.h" | ||
28 | 29 | ||
29 | struct gfs2_attr { | 30 | struct gfs2_attr { |
30 | struct attribute attr; | 31 | struct attribute attr; |
@@ -376,7 +377,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
376 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { | 377 | list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { |
377 | if (jd->jd_jid != jid) | 378 | if (jd->jd_jid != jid) |
378 | continue; | 379 | continue; |
379 | rv = slow_work_enqueue(&jd->jd_work); | 380 | rv = gfs2_recover_journal(jd, false); |
380 | break; | 381 | break; |
381 | } | 382 | } |
382 | out: | 383 | out: |