diff options
author | Benjamin Coddington <bcodding@redhat.com> | 2016-01-06 10:40:18 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-07 18:42:51 -0500 |
commit | 210c7c1750fdf769647d1d526c9ea34c412c9eee (patch) | |
tree | d3e6e91f525fad7ab5fb23f38075af32184cc87c | |
parent | 942e3d72a62dcfe5bf1569b179174718bbbcfbc3 (diff) |
NFS: Use wait_on_atomic_t() for unlock after readahead
The use of wait_on_atomic_t() for waiting on I/O to complete before
unlocking allows us to git rid of the NFS_IO_INPROGRESS flag, and thus the
nfs_iocounter's flags member, and finally the nfs_iocounter altogether.
The count of I/O is moved to the lock context, and the counter
increment/decrement functions become simple enough to open-code.
Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
[Trond: Fix up conflict with existing function nfs_wait_atomic_killable()]
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/file.c | 2 | ||||
-rw-r--r-- | fs/nfs/inode.c | 18 | ||||
-rw-r--r-- | fs/nfs/internal.h | 9 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 48 | ||||
-rw-r--r-- | fs/nfs/write.c | 8 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 8 |
6 files changed, 23 insertions, 70 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 178ec8da028f..4ef8f5addcad 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -756,7 +756,7 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
756 | 756 | ||
757 | l_ctx = nfs_get_lock_context(nfs_file_open_context(filp)); | 757 | l_ctx = nfs_get_lock_context(nfs_file_open_context(filp)); |
758 | if (!IS_ERR(l_ctx)) { | 758 | if (!IS_ERR(l_ctx)) { |
759 | status = nfs_iocounter_wait(&l_ctx->io_count); | 759 | status = nfs_iocounter_wait(l_ctx); |
760 | nfs_put_lock_context(l_ctx); | 760 | nfs_put_lock_context(l_ctx); |
761 | if (status < 0) | 761 | if (status < 0) |
762 | return status; | 762 | return status; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 74fb1223c2f5..4b63d1bd5820 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -71,19 +71,25 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | |||
71 | return nfs_fileid_to_ino_t(fattr->fileid); | 71 | return nfs_fileid_to_ino_t(fattr->fileid); |
72 | } | 72 | } |
73 | 73 | ||
74 | /** | 74 | static int nfs_wait_killable(int mode) |
75 | * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks | ||
76 | * @word: long word containing the bit lock | ||
77 | */ | ||
78 | int nfs_wait_bit_killable(struct wait_bit_key *key, int mode) | ||
79 | { | 75 | { |
80 | freezable_schedule_unsafe(); | 76 | freezable_schedule_unsafe(); |
81 | if (signal_pending_state(mode, current)) | 77 | if (signal_pending_state(mode, current)) |
82 | return -ERESTARTSYS; | 78 | return -ERESTARTSYS; |
83 | return 0; | 79 | return 0; |
84 | } | 80 | } |
81 | |||
82 | int nfs_wait_bit_killable(struct wait_bit_key *key, int mode) | ||
83 | { | ||
84 | return nfs_wait_killable(mode); | ||
85 | } | ||
85 | EXPORT_SYMBOL_GPL(nfs_wait_bit_killable); | 86 | EXPORT_SYMBOL_GPL(nfs_wait_bit_killable); |
86 | 87 | ||
88 | int nfs_wait_atomic_killable(atomic_t *p) | ||
89 | { | ||
90 | return nfs_wait_killable(TASK_KILLABLE); | ||
91 | } | ||
92 | |||
87 | /** | 93 | /** |
88 | * nfs_compat_user_ino64 - returns the user-visible inode number | 94 | * nfs_compat_user_ino64 - returns the user-visible inode number |
89 | * @fileid: 64-bit fileid | 95 | * @fileid: 64-bit fileid |
@@ -699,7 +705,7 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | |||
699 | l_ctx->lockowner.l_owner = current->files; | 705 | l_ctx->lockowner.l_owner = current->files; |
700 | l_ctx->lockowner.l_pid = current->tgid; | 706 | l_ctx->lockowner.l_pid = current->tgid; |
701 | INIT_LIST_HEAD(&l_ctx->list); | 707 | INIT_LIST_HEAD(&l_ctx->list); |
702 | nfs_iocounter_init(&l_ctx->io_count); | 708 | atomic_set(&l_ctx->io_count, 0); |
703 | } | 709 | } |
704 | 710 | ||
705 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | 711 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index ee81792d2886..4e8cc942336c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -238,7 +238,7 @@ extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, | |||
238 | struct nfs_pgio_header *hdr, | 238 | struct nfs_pgio_header *hdr, |
239 | void (*release)(struct nfs_pgio_header *hdr)); | 239 | void (*release)(struct nfs_pgio_header *hdr)); |
240 | void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); | 240 | void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); |
241 | int nfs_iocounter_wait(struct nfs_io_counter *c); | 241 | int nfs_iocounter_wait(struct nfs_lock_context *l_ctx); |
242 | 242 | ||
243 | extern const struct nfs_pageio_ops nfs_pgio_rw_ops; | 243 | extern const struct nfs_pageio_ops nfs_pgio_rw_ops; |
244 | struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); | 244 | struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); |
@@ -252,12 +252,6 @@ void nfs_free_request(struct nfs_page *req); | |||
252 | struct nfs_pgio_mirror * | 252 | struct nfs_pgio_mirror * |
253 | nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc); | 253 | nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc); |
254 | 254 | ||
255 | static inline void nfs_iocounter_init(struct nfs_io_counter *c) | ||
256 | { | ||
257 | c->flags = 0; | ||
258 | atomic_set(&c->io_count, 0); | ||
259 | } | ||
260 | |||
261 | static inline bool nfs_pgio_has_mirroring(struct nfs_pageio_descriptor *desc) | 255 | static inline bool nfs_pgio_has_mirroring(struct nfs_pageio_descriptor *desc) |
262 | { | 256 | { |
263 | WARN_ON_ONCE(desc->pg_mirror_count < 1); | 257 | WARN_ON_ONCE(desc->pg_mirror_count < 1); |
@@ -386,6 +380,7 @@ extern void nfs_clear_inode(struct inode *); | |||
386 | extern void nfs_evict_inode(struct inode *); | 380 | extern void nfs_evict_inode(struct inode *); |
387 | void nfs_zap_acl_cache(struct inode *inode); | 381 | void nfs_zap_acl_cache(struct inode *inode); |
388 | extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode); | 382 | extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode); |
383 | extern int nfs_wait_atomic_killable(atomic_t *p); | ||
389 | 384 | ||
390 | /* super.c */ | 385 | /* super.c */ |
391 | extern const struct super_operations nfs_sops; | 386 | extern const struct super_operations nfs_sops; |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index eeddbf0bf4c4..cb7e73ba059c 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -101,53 +101,18 @@ nfs_page_free(struct nfs_page *p) | |||
101 | kmem_cache_free(nfs_page_cachep, p); | 101 | kmem_cache_free(nfs_page_cachep, p); |
102 | } | 102 | } |
103 | 103 | ||
104 | static void | ||
105 | nfs_iocounter_inc(struct nfs_io_counter *c) | ||
106 | { | ||
107 | atomic_inc(&c->io_count); | ||
108 | } | ||
109 | |||
110 | static void | ||
111 | nfs_iocounter_dec(struct nfs_io_counter *c) | ||
112 | { | ||
113 | if (atomic_dec_and_test(&c->io_count)) { | ||
114 | clear_bit(NFS_IO_INPROGRESS, &c->flags); | ||
115 | smp_mb__after_atomic(); | ||
116 | wake_up_bit(&c->flags, NFS_IO_INPROGRESS); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | __nfs_iocounter_wait(struct nfs_io_counter *c) | ||
122 | { | ||
123 | wait_queue_head_t *wq = bit_waitqueue(&c->flags, NFS_IO_INPROGRESS); | ||
124 | DEFINE_WAIT_BIT(q, &c->flags, NFS_IO_INPROGRESS); | ||
125 | int ret = 0; | ||
126 | |||
127 | do { | ||
128 | prepare_to_wait(wq, &q.wait, TASK_KILLABLE); | ||
129 | set_bit(NFS_IO_INPROGRESS, &c->flags); | ||
130 | if (atomic_read(&c->io_count) == 0) | ||
131 | break; | ||
132 | ret = nfs_wait_bit_killable(&q.key, TASK_KILLABLE); | ||
133 | } while (atomic_read(&c->io_count) != 0 && !ret); | ||
134 | finish_wait(wq, &q.wait); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | /** | 104 | /** |
139 | * nfs_iocounter_wait - wait for i/o to complete | 105 | * nfs_iocounter_wait - wait for i/o to complete |
140 | * @c: nfs_io_counter to use | 106 | * @l_ctx: nfs_lock_context with io_counter to use |
141 | * | 107 | * |
142 | * returns -ERESTARTSYS if interrupted by a fatal signal. | 108 | * returns -ERESTARTSYS if interrupted by a fatal signal. |
143 | * Otherwise returns 0 once the io_count hits 0. | 109 | * Otherwise returns 0 once the io_count hits 0. |
144 | */ | 110 | */ |
145 | int | 111 | int |
146 | nfs_iocounter_wait(struct nfs_io_counter *c) | 112 | nfs_iocounter_wait(struct nfs_lock_context *l_ctx) |
147 | { | 113 | { |
148 | if (atomic_read(&c->io_count) == 0) | 114 | return wait_on_atomic_t(&l_ctx->io_count, nfs_wait_atomic_killable, |
149 | return 0; | 115 | TASK_KILLABLE); |
150 | return __nfs_iocounter_wait(c); | ||
151 | } | 116 | } |
152 | 117 | ||
153 | /* | 118 | /* |
@@ -370,7 +335,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page, | |||
370 | return ERR_CAST(l_ctx); | 335 | return ERR_CAST(l_ctx); |
371 | } | 336 | } |
372 | req->wb_lock_context = l_ctx; | 337 | req->wb_lock_context = l_ctx; |
373 | nfs_iocounter_inc(&l_ctx->io_count); | 338 | atomic_inc(&l_ctx->io_count); |
374 | 339 | ||
375 | /* Initialize the request struct. Initially, we assume a | 340 | /* Initialize the request struct. Initially, we assume a |
376 | * long write-back delay. This will be adjusted in | 341 | * long write-back delay. This will be adjusted in |
@@ -431,7 +396,8 @@ static void nfs_clear_request(struct nfs_page *req) | |||
431 | req->wb_page = NULL; | 396 | req->wb_page = NULL; |
432 | } | 397 | } |
433 | if (l_ctx != NULL) { | 398 | if (l_ctx != NULL) { |
434 | nfs_iocounter_dec(&l_ctx->io_count); | 399 | if (atomic_dec_and_test(&l_ctx->io_count)) |
400 | wake_up_atomic_t(&l_ctx->io_count); | ||
435 | nfs_put_lock_context(l_ctx); | 401 | nfs_put_lock_context(l_ctx); |
436 | req->wb_lock_context = NULL; | 402 | req->wb_lock_context = NULL; |
437 | } | 403 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 94828b3f8c95..8ba4f717b413 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1565,14 +1565,6 @@ static void nfs_writeback_result(struct rpc_task *task, | |||
1565 | } | 1565 | } |
1566 | } | 1566 | } |
1567 | 1567 | ||
1568 | static int nfs_wait_atomic_killable(atomic_t *key) | ||
1569 | { | ||
1570 | if (fatal_signal_pending(current)) | ||
1571 | return -ERESTARTSYS; | ||
1572 | freezable_schedule_unsafe(); | ||
1573 | return 0; | ||
1574 | } | ||
1575 | |||
1576 | static int wait_on_commit(struct nfs_mds_commit_info *cinfo) | 1568 | static int wait_on_commit(struct nfs_mds_commit_info *cinfo) |
1577 | { | 1569 | { |
1578 | return wait_on_atomic_t(&cinfo->rpcs_out, | 1570 | return wait_on_atomic_t(&cinfo->rpcs_out, |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 9eee972863a7..196aaceafda7 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -60,18 +60,12 @@ struct nfs_lockowner { | |||
60 | pid_t l_pid; | 60 | pid_t l_pid; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | #define NFS_IO_INPROGRESS 0 | ||
64 | struct nfs_io_counter { | ||
65 | unsigned long flags; | ||
66 | atomic_t io_count; | ||
67 | }; | ||
68 | |||
69 | struct nfs_lock_context { | 63 | struct nfs_lock_context { |
70 | atomic_t count; | 64 | atomic_t count; |
71 | struct list_head list; | 65 | struct list_head list; |
72 | struct nfs_open_context *open_context; | 66 | struct nfs_open_context *open_context; |
73 | struct nfs_lockowner lockowner; | 67 | struct nfs_lockowner lockowner; |
74 | struct nfs_io_counter io_count; | 68 | atomic_t io_count; |
75 | }; | 69 | }; |
76 | 70 | ||
77 | struct nfs4_state; | 71 | struct nfs4_state; |