1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Common NFS I/O operations for the pnfs file based
4 * layout drivers.
5 *
6 * Copyright (c) 2014, Primary Data, Inc. All rights reserved.
7 *
8 * Tom Haynes <loghyr@primarydata.com>
9 */
10
11 #include <linux/nfs_fs.h>
12 #include <linux/nfs_page.h>
13 #include <linux/sunrpc/addr.h>
14 #include <linux/module.h>
15
16 #include "nfs4session.h"
17 #include "internal.h"
18 #include "pnfs.h"
19 #include "netns.h"
20 #include "nfs4trace.h"
21
22 #define NFSDBG_FACILITY NFSDBG_PNFS
23
pnfs_generic_rw_release(void * data)24 void pnfs_generic_rw_release(void *data)
25 {
26 struct nfs_pgio_header *hdr = data;
27
28 nfs_put_client(hdr->ds_clp);
29 hdr->mds_ops->rpc_release(data);
30 }
31 EXPORT_SYMBOL_GPL(pnfs_generic_rw_release);
32
33 /* Fake up some data that will cause nfs_commit_release to retry the writes. */
pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data * data)34 void pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data *data)
35 {
36 struct nfs_writeverf *verf = data->res.verf;
37
38 data->task.tk_status = 0;
39 memset(&verf->verifier, 0, sizeof(verf->verifier));
40 verf->committed = NFS_UNSTABLE;
41 }
42 EXPORT_SYMBOL_GPL(pnfs_generic_prepare_to_resend_writes);
43
pnfs_generic_write_commit_done(struct rpc_task * task,void * data)44 void pnfs_generic_write_commit_done(struct rpc_task *task, void *data)
45 {
46 struct nfs_commit_data *wdata = data;
47
48 /* Note this may cause RPC to be resent */
49 wdata->mds_ops->rpc_call_done(task, data);
50 }
51 EXPORT_SYMBOL_GPL(pnfs_generic_write_commit_done);
52
pnfs_generic_commit_release(void * calldata)53 void pnfs_generic_commit_release(void *calldata)
54 {
55 struct nfs_commit_data *data = calldata;
56
57 data->completion_ops->completion(data);
58 pnfs_put_lseg(data->lseg);
59 nfs_put_client(data->ds_clp);
60 nfs_commitdata_release(data);
61 }
62 EXPORT_SYMBOL_GPL(pnfs_generic_commit_release);
63
64 static struct pnfs_layout_segment *
pnfs_free_bucket_lseg(struct pnfs_commit_bucket * bucket)65 pnfs_free_bucket_lseg(struct pnfs_commit_bucket *bucket)
66 {
67 if (list_empty(&bucket->committing) && list_empty(&bucket->written)) {
68 struct pnfs_layout_segment *freeme = bucket->lseg;
69 bucket->lseg = NULL;
70 return freeme;
71 }
72 return NULL;
73 }
74
75 /* The generic layer is about to remove the req from the commit list.
76 * If this will make the bucket empty, it will need to put the lseg reference.
77 * Note this must be called holding nfsi->commit_mutex
78 */
79 void
pnfs_generic_clear_request_commit(struct nfs_page * req,struct nfs_commit_info * cinfo)80 pnfs_generic_clear_request_commit(struct nfs_page *req,
81 struct nfs_commit_info *cinfo)
82 {
83 struct pnfs_commit_bucket *bucket = NULL;
84
85 if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
86 goto out;
87 cinfo->ds->nwritten--;
88 if (list_is_singular(&req->wb_list))
89 bucket = list_first_entry(&req->wb_list,
90 struct pnfs_commit_bucket, written);
91 out:
92 nfs_request_remove_commit_list(req, cinfo);
93 if (bucket)
94 pnfs_put_lseg(pnfs_free_bucket_lseg(bucket));
95 }
96 EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);
97
98 struct pnfs_commit_array *
pnfs_alloc_commit_array(size_t n,gfp_t gfp_flags)99 pnfs_alloc_commit_array(size_t n, gfp_t gfp_flags)
100 {
101 struct pnfs_commit_array *p;
102 struct pnfs_commit_bucket *b;
103
104 p = kmalloc_flex(*p, buckets, n, gfp_flags);
105 if (!p)
106 return NULL;
107 p->nbuckets = n;
108 INIT_LIST_HEAD(&p->cinfo_list);
109 INIT_LIST_HEAD(&p->lseg_list);
110 p->lseg = NULL;
111 for (b = &p->buckets[0]; n != 0; b++, n--) {
112 INIT_LIST_HEAD(&b->written);
113 INIT_LIST_HEAD(&b->committing);
114 b->lseg = NULL;
115 b->direct_verf.committed = NFS_INVALID_STABLE_HOW;
116 }
117 return p;
118 }
119 EXPORT_SYMBOL_GPL(pnfs_alloc_commit_array);
120
121 void
pnfs_free_commit_array(struct pnfs_commit_array * p)122 pnfs_free_commit_array(struct pnfs_commit_array *p)
123 {
124 kfree_rcu(p, rcu);
125 }
126 EXPORT_SYMBOL_GPL(pnfs_free_commit_array);
127
128 static struct pnfs_commit_array *
pnfs_find_commit_array_by_lseg(struct pnfs_ds_commit_info * fl_cinfo,struct pnfs_layout_segment * lseg)129 pnfs_find_commit_array_by_lseg(struct pnfs_ds_commit_info *fl_cinfo,
130 struct pnfs_layout_segment *lseg)
131 {
132 struct pnfs_commit_array *array;
133
134 list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
135 if (array->lseg == lseg)
136 return array;
137 }
138 return NULL;
139 }
140
141 struct pnfs_commit_array *
pnfs_add_commit_array(struct pnfs_ds_commit_info * fl_cinfo,struct pnfs_commit_array * new,struct pnfs_layout_segment * lseg)142 pnfs_add_commit_array(struct pnfs_ds_commit_info *fl_cinfo,
143 struct pnfs_commit_array *new,
144 struct pnfs_layout_segment *lseg)
145 {
146 struct pnfs_commit_array *array;
147
148 array = pnfs_find_commit_array_by_lseg(fl_cinfo, lseg);
149 if (array)
150 return array;
151 new->lseg = lseg;
152 refcount_set(&new->refcount, 1);
153 list_add_rcu(&new->cinfo_list, &fl_cinfo->commits);
154 list_add(&new->lseg_list, &lseg->pls_commits);
155 return new;
156 }
157 EXPORT_SYMBOL_GPL(pnfs_add_commit_array);
158
159 static struct pnfs_commit_array *
pnfs_lookup_commit_array(struct pnfs_ds_commit_info * fl_cinfo,struct pnfs_layout_segment * lseg)160 pnfs_lookup_commit_array(struct pnfs_ds_commit_info *fl_cinfo,
161 struct pnfs_layout_segment *lseg)
162 {
163 struct pnfs_commit_array *array;
164
165 rcu_read_lock();
166 array = pnfs_find_commit_array_by_lseg(fl_cinfo, lseg);
167 if (!array) {
168 rcu_read_unlock();
169 fl_cinfo->ops->setup_ds_info(fl_cinfo, lseg);
170 rcu_read_lock();
171 array = pnfs_find_commit_array_by_lseg(fl_cinfo, lseg);
172 }
173 rcu_read_unlock();
174 return array;
175 }
176
177 static void
pnfs_release_commit_array_locked(struct pnfs_commit_array * array)178 pnfs_release_commit_array_locked(struct pnfs_commit_array *array)
179 {
180 list_del_rcu(&array->cinfo_list);
181 list_del(&array->lseg_list);
182 pnfs_free_commit_array(array);
183 }
184
185 static void
pnfs_put_commit_array_locked(struct pnfs_commit_array * array)186 pnfs_put_commit_array_locked(struct pnfs_commit_array *array)
187 {
188 if (refcount_dec_and_test(&array->refcount))
189 pnfs_release_commit_array_locked(array);
190 }
191
192 static void
pnfs_put_commit_array(struct pnfs_commit_array * array,struct inode * inode)193 pnfs_put_commit_array(struct pnfs_commit_array *array, struct inode *inode)
194 {
195 if (refcount_dec_and_lock(&array->refcount, &inode->i_lock)) {
196 pnfs_release_commit_array_locked(array);
197 spin_unlock(&inode->i_lock);
198 }
199 }
200
201 static struct pnfs_commit_array *
pnfs_get_commit_array(struct pnfs_commit_array * array)202 pnfs_get_commit_array(struct pnfs_commit_array *array)
203 {
204 if (refcount_inc_not_zero(&array->refcount))
205 return array;
206 return NULL;
207 }
208
209 static void
pnfs_remove_and_free_commit_array(struct pnfs_commit_array * array)210 pnfs_remove_and_free_commit_array(struct pnfs_commit_array *array)
211 {
212 array->lseg = NULL;
213 list_del_init(&array->lseg_list);
214 pnfs_put_commit_array_locked(array);
215 }
216
217 void
pnfs_generic_ds_cinfo_release_lseg(struct pnfs_ds_commit_info * fl_cinfo,struct pnfs_layout_segment * lseg)218 pnfs_generic_ds_cinfo_release_lseg(struct pnfs_ds_commit_info *fl_cinfo,
219 struct pnfs_layout_segment *lseg)
220 {
221 struct pnfs_commit_array *array, *tmp;
222
223 list_for_each_entry_safe(array, tmp, &lseg->pls_commits, lseg_list)
224 pnfs_remove_and_free_commit_array(array);
225 }
226 EXPORT_SYMBOL_GPL(pnfs_generic_ds_cinfo_release_lseg);
227
228 void
pnfs_generic_ds_cinfo_destroy(struct pnfs_ds_commit_info * fl_cinfo)229 pnfs_generic_ds_cinfo_destroy(struct pnfs_ds_commit_info *fl_cinfo)
230 {
231 struct pnfs_commit_array *array, *tmp;
232
233 list_for_each_entry_safe(array, tmp, &fl_cinfo->commits, cinfo_list)
234 pnfs_remove_and_free_commit_array(array);
235 }
236 EXPORT_SYMBOL_GPL(pnfs_generic_ds_cinfo_destroy);
237
238 /*
239 * Locks the nfs_page requests for commit and moves them to
240 * @bucket->committing.
241 */
242 static int
pnfs_bucket_scan_ds_commit_list(struct pnfs_commit_bucket * bucket,struct nfs_commit_info * cinfo,int max)243 pnfs_bucket_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
244 struct nfs_commit_info *cinfo,
245 int max)
246 {
247 struct list_head *src = &bucket->written;
248 struct list_head *dst = &bucket->committing;
249 int ret;
250
251 lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
252 ret = nfs_scan_commit_list(src, dst, cinfo, max);
253 if (ret) {
254 cinfo->ds->nwritten -= ret;
255 cinfo->ds->ncommitting += ret;
256 }
257 return ret;
258 }
259
pnfs_bucket_scan_array(struct nfs_commit_info * cinfo,struct pnfs_commit_bucket * buckets,unsigned int nbuckets,int max)260 static int pnfs_bucket_scan_array(struct nfs_commit_info *cinfo,
261 struct pnfs_commit_bucket *buckets,
262 unsigned int nbuckets,
263 int max)
264 {
265 unsigned int i;
266 int rv = 0, cnt;
267
268 for (i = 0; i < nbuckets && max != 0; i++) {
269 cnt = pnfs_bucket_scan_ds_commit_list(&buckets[i], cinfo, max);
270 rv += cnt;
271 max -= cnt;
272 }
273 return rv;
274 }
275
276 /* Move reqs from written to committing lists, returning count
277 * of number moved.
278 */
pnfs_generic_scan_commit_lists(struct nfs_commit_info * cinfo,int max)279 int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max)
280 {
281 struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
282 struct pnfs_commit_array *array;
283 int rv = 0, cnt;
284
285 rcu_read_lock();
286 list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
287 if (!array->lseg || !pnfs_get_commit_array(array))
288 continue;
289 rcu_read_unlock();
290 cnt = pnfs_bucket_scan_array(cinfo, array->buckets,
291 array->nbuckets, max);
292 rcu_read_lock();
293 pnfs_put_commit_array(array, cinfo->inode);
294 rv += cnt;
295 max -= cnt;
296 if (!max)
297 break;
298 }
299 rcu_read_unlock();
300 return rv;
301 }
302 EXPORT_SYMBOL_GPL(pnfs_generic_scan_commit_lists);
303
304 static unsigned int
pnfs_bucket_recover_commit_reqs(struct list_head * dst,struct pnfs_commit_bucket * buckets,unsigned int nbuckets,struct nfs_commit_info * cinfo)305 pnfs_bucket_recover_commit_reqs(struct list_head *dst,
306 struct pnfs_commit_bucket *buckets,
307 unsigned int nbuckets,
308 struct nfs_commit_info *cinfo)
309 {
310 struct pnfs_commit_bucket *b;
311 struct pnfs_layout_segment *freeme;
312 unsigned int nwritten, ret = 0;
313 unsigned int i;
314
315 restart:
316 for (i = 0, b = buckets; i < nbuckets; i++, b++) {
317 nwritten = nfs_scan_commit_list(&b->written, dst, cinfo, 0);
318 if (!nwritten)
319 continue;
320 ret += nwritten;
321 freeme = pnfs_free_bucket_lseg(b);
322 if (freeme) {
323 pnfs_put_lseg(freeme);
324 goto restart;
325 }
326 }
327 return ret;
328 }
329
330 /* Pull everything off the committing lists and dump into @dst. */
pnfs_generic_recover_commit_reqs(struct list_head * dst,struct nfs_commit_info * cinfo)331 void pnfs_generic_recover_commit_reqs(struct list_head *dst,
332 struct nfs_commit_info *cinfo)
333 {
334 struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
335 struct pnfs_commit_array *array;
336 unsigned int nwritten;
337
338 lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
339 rcu_read_lock();
340 list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
341 if (!array->lseg || !pnfs_get_commit_array(array))
342 continue;
343 rcu_read_unlock();
344 nwritten = pnfs_bucket_recover_commit_reqs(dst,
345 array->buckets,
346 array->nbuckets,
347 cinfo);
348 rcu_read_lock();
349 pnfs_put_commit_array(array, cinfo->inode);
350 fl_cinfo->nwritten -= nwritten;
351 }
352 rcu_read_unlock();
353 }
354 EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
355
356 static struct pnfs_layout_segment *
pnfs_bucket_get_committing(struct list_head * head,struct pnfs_commit_bucket * bucket,struct nfs_commit_info * cinfo)357 pnfs_bucket_get_committing(struct list_head *head,
358 struct pnfs_commit_bucket *bucket,
359 struct nfs_commit_info *cinfo)
360 {
361 struct pnfs_layout_segment *lseg;
362 struct list_head *pos;
363
364 list_for_each(pos, &bucket->committing)
365 cinfo->ds->ncommitting--;
366 list_splice_init(&bucket->committing, head);
367 lseg = pnfs_free_bucket_lseg(bucket);
368 if (!lseg)
369 lseg = pnfs_get_lseg(bucket->lseg);
370 return lseg;
371 }
372
373 static struct nfs_commit_data *
pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket * bucket,struct nfs_commit_info * cinfo)374 pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
375 struct nfs_commit_info *cinfo)
376 {
377 struct nfs_commit_data *data = nfs_commitdata_alloc();
378
379 if (!data)
380 return NULL;
381 data->lseg = pnfs_bucket_get_committing(&data->pages, bucket, cinfo);
382 return data;
383 }
384
pnfs_generic_retry_commit(struct pnfs_commit_bucket * buckets,unsigned int nbuckets,struct nfs_commit_info * cinfo,unsigned int idx)385 static void pnfs_generic_retry_commit(struct pnfs_commit_bucket *buckets,
386 unsigned int nbuckets,
387 struct nfs_commit_info *cinfo,
388 unsigned int idx)
389 {
390 struct pnfs_commit_bucket *bucket;
391 struct pnfs_layout_segment *freeme;
392 LIST_HEAD(pages);
393
394 for (bucket = buckets; idx < nbuckets; bucket++, idx++) {
395 if (list_empty(&bucket->committing))
396 continue;
397 mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
398 freeme = pnfs_bucket_get_committing(&pages, bucket, cinfo);
399 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
400 nfs_retry_commit(&pages, freeme, cinfo, idx);
401 pnfs_put_lseg(freeme);
402 }
403 }
404
405 static unsigned int
pnfs_bucket_alloc_ds_commits(struct list_head * list,struct pnfs_commit_bucket * buckets,unsigned int nbuckets,struct nfs_commit_info * cinfo)406 pnfs_bucket_alloc_ds_commits(struct list_head *list,
407 struct pnfs_commit_bucket *buckets,
408 unsigned int nbuckets,
409 struct nfs_commit_info *cinfo)
410 {
411 struct pnfs_commit_bucket *bucket;
412 struct nfs_commit_data *data;
413 unsigned int i;
414 unsigned int nreq = 0;
415
416 for (i = 0, bucket = buckets; i < nbuckets; i++, bucket++) {
417 if (list_empty(&bucket->committing))
418 continue;
419 mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
420 if (!list_empty(&bucket->committing)) {
421 data = pnfs_bucket_fetch_commitdata(bucket, cinfo);
422 if (!data)
423 goto out_error;
424 data->ds_commit_index = i;
425 list_add_tail(&data->list, list);
426 nreq++;
427 }
428 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
429 }
430 return nreq;
431 out_error:
432 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
433 /* Clean up on error */
434 pnfs_generic_retry_commit(buckets, nbuckets, cinfo, i);
435 return nreq;
436 }
437
438 static unsigned int
pnfs_alloc_ds_commits_list(struct list_head * list,struct pnfs_ds_commit_info * fl_cinfo,struct nfs_commit_info * cinfo)439 pnfs_alloc_ds_commits_list(struct list_head *list,
440 struct pnfs_ds_commit_info *fl_cinfo,
441 struct nfs_commit_info *cinfo)
442 {
443 struct pnfs_commit_array *array;
444 unsigned int ret = 0;
445
446 rcu_read_lock();
447 list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
448 if (!array->lseg || !pnfs_get_commit_array(array))
449 continue;
450 rcu_read_unlock();
451 ret += pnfs_bucket_alloc_ds_commits(list, array->buckets,
452 array->nbuckets, cinfo);
453 rcu_read_lock();
454 pnfs_put_commit_array(array, cinfo->inode);
455 }
456 rcu_read_unlock();
457 return ret;
458 }
459
460 /* This follows nfs_commit_list pretty closely */
461 int
pnfs_generic_commit_pagelist(struct inode * inode,struct list_head * mds_pages,int how,struct nfs_commit_info * cinfo,int (* initiate_commit)(struct nfs_commit_data * data,int how))462 pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
463 int how, struct nfs_commit_info *cinfo,
464 int (*initiate_commit)(struct nfs_commit_data *data,
465 int how))
466 {
467 struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
468 struct nfs_commit_data *data, *tmp;
469 LIST_HEAD(list);
470 unsigned int nreq = 0;
471
472 if (!list_empty(mds_pages)) {
473 data = nfs_commitdata_alloc();
474 if (!data) {
475 nfs_retry_commit(mds_pages, NULL, cinfo, -1);
476 return -ENOMEM;
477 }
478 data->ds_commit_index = -1;
479 list_splice_init(mds_pages, &data->pages);
480 list_add_tail(&data->list, &list);
481 nreq++;
482 }
483
484 nreq += pnfs_alloc_ds_commits_list(&list, fl_cinfo, cinfo);
485 if (nreq == 0)
486 goto out;
487
488 list_for_each_entry_safe(data, tmp, &list, list) {
489 list_del(&data->list);
490 if (data->ds_commit_index < 0) {
491 nfs_init_commit(data, NULL, NULL, cinfo);
492 nfs_initiate_commit(NFS_CLIENT(inode), data,
493 NFS_PROTO(data->inode),
494 data->mds_ops, how,
495 RPC_TASK_CRED_NOREF, NULL);
496 } else {
497 nfs_init_commit(data, NULL, data->lseg, cinfo);
498 initiate_commit(data, how);
499 }
500 }
501 out:
502 return PNFS_ATTEMPTED;
503 }
504 EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
505
506 /*
507 * Data server cache
508 *
509 * Data servers can be mapped to different device ids, but should
510 * never be shared between net namespaces.
511 *
512 * nfs4_pnfs_ds reference counting:
513 * - set to 1 on allocation
514 * - incremented when a device id maps a data server already in the cache.
515 * - decremented when deviceid is removed from the cache.
516 */
517
518 /* Debug routines */
519 static void
print_ds(struct nfs4_pnfs_ds * ds)520 print_ds(struct nfs4_pnfs_ds *ds)
521 {
522 if (ds == NULL) {
523 printk(KERN_WARNING "%s NULL device\n", __func__);
524 return;
525 }
526 printk(KERN_WARNING " ds %s\n"
527 " ref count %d\n"
528 " client %p\n"
529 " cl_exchange_flags %x\n",
530 ds->ds_remotestr,
531 refcount_read(&ds->ds_count), ds->ds_clp,
532 ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
533 }
534
535 static bool
same_sockaddr(struct sockaddr * addr1,struct sockaddr * addr2)536 same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
537 {
538 struct sockaddr_in *a, *b;
539 struct sockaddr_in6 *a6, *b6;
540
541 if (addr1->sa_family != addr2->sa_family)
542 return false;
543
544 switch (addr1->sa_family) {
545 case AF_INET:
546 a = (struct sockaddr_in *)addr1;
547 b = (struct sockaddr_in *)addr2;
548
549 if (a->sin_addr.s_addr == b->sin_addr.s_addr &&
550 a->sin_port == b->sin_port)
551 return true;
552 break;
553
554 case AF_INET6:
555 a6 = (struct sockaddr_in6 *)addr1;
556 b6 = (struct sockaddr_in6 *)addr2;
557
558 /* LINKLOCAL addresses must have matching scope_id */
559 if (ipv6_addr_src_scope(&a6->sin6_addr) ==
560 IPV6_ADDR_SCOPE_LINKLOCAL &&
561 a6->sin6_scope_id != b6->sin6_scope_id)
562 return false;
563
564 if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) &&
565 a6->sin6_port == b6->sin6_port)
566 return true;
567 break;
568
569 default:
570 dprintk("%s: unhandled address family: %u\n",
571 __func__, addr1->sa_family);
572 return false;
573 }
574
575 return false;
576 }
577
578 /*
579 * Checks if 'dsaddrs1' contains a subset of 'dsaddrs2'. If it does,
580 * declare a match.
581 */
582 static bool
_same_data_server_addrs_locked(const struct list_head * dsaddrs1,const struct list_head * dsaddrs2)583 _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
584 const struct list_head *dsaddrs2)
585 {
586 struct nfs4_pnfs_ds_addr *da1, *da2;
587 struct sockaddr *sa1, *sa2;
588 bool match = false;
589
590 list_for_each_entry(da1, dsaddrs1, da_node) {
591 sa1 = (struct sockaddr *)&da1->da_addr;
592 match = false;
593 list_for_each_entry(da2, dsaddrs2, da_node) {
594 sa2 = (struct sockaddr *)&da2->da_addr;
595 match = same_sockaddr(sa1, sa2);
596 if (match)
597 break;
598 }
599 if (!match)
600 break;
601 }
602 return match;
603 }
604
605 /*
606 * Lookup DS by addresses and NFS version. nfs4_ds_cache_lock is held
607 */
608 static struct nfs4_pnfs_ds *
_data_server_lookup_locked(const struct nfs_net * nn,const struct list_head * dsaddrs,u32 version)609 _data_server_lookup_locked(const struct nfs_net *nn,
610 const struct list_head *dsaddrs, u32 version)
611 {
612 struct nfs4_pnfs_ds *ds;
613
614 list_for_each_entry(ds, &nn->nfs4_data_server_cache, ds_node)
615 if (ds->ds_version == version &&
616 _same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
617 return ds;
618 return NULL;
619 }
620
nfs4_pnfs_ds_addr_alloc(gfp_t gfp_flags)621 static struct nfs4_pnfs_ds_addr *nfs4_pnfs_ds_addr_alloc(gfp_t gfp_flags)
622 {
623 struct nfs4_pnfs_ds_addr *da = kzalloc_obj(*da, gfp_flags);
624 if (da)
625 INIT_LIST_HEAD(&da->da_node);
626 return da;
627 }
628
nfs4_pnfs_ds_addr_free(struct nfs4_pnfs_ds_addr * da)629 static void nfs4_pnfs_ds_addr_free(struct nfs4_pnfs_ds_addr *da)
630 {
631 kfree(da->da_remotestr);
632 kfree(da->da_netid);
633 kfree(da);
634 }
635
destroy_ds(struct nfs4_pnfs_ds * ds)636 static void destroy_ds(struct nfs4_pnfs_ds *ds)
637 {
638 struct nfs4_pnfs_ds_addr *da;
639
640 dprintk("--> %s\n", __func__);
641 ifdebug(FACILITY)
642 print_ds(ds);
643
644 nfs_put_client(ds->ds_clp);
645
646 while (!list_empty(&ds->ds_addrs)) {
647 da = list_first_entry(&ds->ds_addrs,
648 struct nfs4_pnfs_ds_addr,
649 da_node);
650 list_del_init(&da->da_node);
651 nfs4_pnfs_ds_addr_free(da);
652 }
653
654 kfree(ds->ds_remotestr);
655 kfree(ds);
656 }
657
nfs4_pnfs_ds_put(struct nfs4_pnfs_ds * ds)658 void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds)
659 {
660 struct nfs_net *nn = net_generic(ds->ds_net, nfs_net_id);
661
662 if (refcount_dec_and_lock(&ds->ds_count, &nn->nfs4_data_server_lock)) {
663 list_del_init(&ds->ds_node);
664 spin_unlock(&nn->nfs4_data_server_lock);
665 destroy_ds(ds);
666 }
667 }
668 EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_put);
669
670 /*
671 * Create a string with a human readable address and port to avoid
672 * complicated setup around many dprinks.
673 */
674 static char *
nfs4_pnfs_remotestr(struct list_head * dsaddrs,gfp_t gfp_flags)675 nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
676 {
677 struct nfs4_pnfs_ds_addr *da;
678 char *remotestr;
679 size_t len;
680 char *p;
681
682 len = 3; /* '{', '}' and eol */
683 list_for_each_entry(da, dsaddrs, da_node) {
684 len += strlen(da->da_remotestr) + 1; /* string plus comma */
685 }
686
687 remotestr = kzalloc(len, gfp_flags);
688 if (!remotestr)
689 return NULL;
690
691 p = remotestr;
692 *(p++) = '{';
693 len--;
694 list_for_each_entry(da, dsaddrs, da_node) {
695 size_t ll = strlen(da->da_remotestr);
696
697 if (ll > len)
698 goto out_err;
699
700 memcpy(p, da->da_remotestr, ll);
701 p += ll;
702 len -= ll;
703
704 if (len < 1)
705 goto out_err;
706 (*p++) = ',';
707 len--;
708 }
709 if (len < 2)
710 goto out_err;
711 *(p++) = '}';
712 *p = '\0';
713 return remotestr;
714 out_err:
715 kfree(remotestr);
716 return NULL;
717 }
718
719 /*
720 * Given a list of multipath struct nfs4_pnfs_ds_addr, add it to ds cache if
721 * uncached and return cached struct nfs4_pnfs_ds.
722 */
723 struct nfs4_pnfs_ds *
nfs4_pnfs_ds_add(const struct net * net,struct list_head * dsaddrs,u32 version,gfp_t gfp_flags)724 nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, u32 version,
725 gfp_t gfp_flags)
726 {
727 struct nfs_net *nn = net_generic(net, nfs_net_id);
728 struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
729 char *remotestr;
730
731 if (list_empty(dsaddrs)) {
732 dprintk("%s: no addresses defined\n", __func__);
733 goto out;
734 }
735
736 ds = kzalloc_obj(*ds, gfp_flags);
737 if (!ds)
738 goto out;
739
740 /* this is only used for debugging, so it's ok if its NULL */
741 remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
742
743 spin_lock(&nn->nfs4_data_server_lock);
744 tmp_ds = _data_server_lookup_locked(nn, dsaddrs, version);
745 if (tmp_ds == NULL) {
746 INIT_LIST_HEAD(&ds->ds_addrs);
747 list_splice_init(dsaddrs, &ds->ds_addrs);
748 ds->ds_remotestr = remotestr;
749 refcount_set(&ds->ds_count, 1);
750 INIT_LIST_HEAD(&ds->ds_node);
751 ds->ds_net = net;
752 ds->ds_clp = NULL;
753 ds->ds_version = version;
754 list_add(&ds->ds_node, &nn->nfs4_data_server_cache);
755 dprintk("%s add new data server %s\n", __func__,
756 ds->ds_remotestr);
757 } else {
758 kfree(remotestr);
759 kfree(ds);
760 refcount_inc(&tmp_ds->ds_count);
761 dprintk("%s data server %s found, inc'ed ds_count to %d\n",
762 __func__, tmp_ds->ds_remotestr,
763 refcount_read(&tmp_ds->ds_count));
764 ds = tmp_ds;
765 }
766 spin_unlock(&nn->nfs4_data_server_lock);
767 out:
768 return ds;
769 }
770 EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add);
771
nfs4_wait_ds_connect(struct nfs4_pnfs_ds * ds)772 static int nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
773 {
774 might_sleep();
775 return wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, TASK_KILLABLE);
776 }
777
nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds * ds)778 static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
779 {
780 smp_mb__before_atomic();
781 clear_and_wake_up_bit(NFS4DS_CONNECTING, &ds->ds_state);
782 }
783
784 static struct nfs_client *(*get_v3_ds_connect)(
785 struct nfs_server *mds_srv,
786 const struct sockaddr_storage *ds_addr,
787 int ds_addrlen,
788 int ds_proto,
789 unsigned int ds_timeo,
790 unsigned int ds_retrans);
791
load_v3_ds_connect(void)792 static bool load_v3_ds_connect(void)
793 {
794 if (!get_v3_ds_connect) {
795 get_v3_ds_connect = symbol_request(nfs3_set_ds_client);
796 WARN_ON_ONCE(!get_v3_ds_connect);
797 }
798
799 return(get_v3_ds_connect != NULL);
800 }
801
nfs4_pnfs_v3_ds_connect_unload(void)802 void nfs4_pnfs_v3_ds_connect_unload(void)
803 {
804 if (get_v3_ds_connect) {
805 symbol_put(nfs3_set_ds_client);
806 get_v3_ds_connect = NULL;
807 }
808 }
809
_nfs4_pnfs_v3_ds_connect(struct nfs_server * mds_srv,struct nfs4_pnfs_ds * ds,unsigned int timeo,unsigned int retrans)810 static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
811 struct nfs4_pnfs_ds *ds,
812 unsigned int timeo,
813 unsigned int retrans)
814 {
815 struct nfs_client *clp = ERR_PTR(-EIO);
816 struct nfs_client *mds_clp = mds_srv->nfs_client;
817 enum xprtsec_policies xprtsec_policy = mds_clp->cl_xprtsec.policy;
818 struct nfs4_pnfs_ds_addr *da;
819 unsigned long connect_timeout = timeo * (retrans + 1) * HZ / 10;
820 int ds_proto;
821 int status = 0;
822
823 dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
824
825 if (!load_v3_ds_connect())
826 return -EPROTONOSUPPORT;
827
828 list_for_each_entry(da, &ds->ds_addrs, da_node) {
829 dprintk("%s: DS %s: trying address %s\n",
830 __func__, ds->ds_remotestr, da->da_remotestr);
831
832 if (!IS_ERR(clp)) {
833 struct xprt_create xprt_args = {
834 .ident = da->da_transport,
835 .net = clp->cl_net,
836 .dstaddr = (struct sockaddr *)&da->da_addr,
837 .addrlen = da->da_addrlen,
838 .servername = clp->cl_hostname,
839 .connect_timeout = connect_timeout,
840 .reconnect_timeout = connect_timeout,
841 .xprtsec = clp->cl_xprtsec,
842 };
843
844 if (xprt_args.ident == XPRT_TRANSPORT_TCP &&
845 clp->cl_proto == XPRT_TRANSPORT_TCP_TLS)
846 xprt_args.ident = XPRT_TRANSPORT_TCP_TLS;
847
848 if (xprt_args.ident != clp->cl_proto)
849 continue;
850 if (xprt_args.dstaddr->sa_family !=
851 clp->cl_addr.ss_family)
852 continue;
853 /* Add this address as an alias */
854 rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
855 rpc_clnt_test_and_add_xprt, NULL);
856 continue;
857 }
858
859 ds_proto = da->da_transport;
860 if (ds_proto == XPRT_TRANSPORT_TCP &&
861 xprtsec_policy != RPC_XPRTSEC_NONE)
862 ds_proto = XPRT_TRANSPORT_TCP_TLS;
863
864 clp = get_v3_ds_connect(mds_srv, &da->da_addr, da->da_addrlen,
865 ds_proto, timeo, retrans);
866 if (IS_ERR(clp))
867 continue;
868 clp->cl_rpcclient->cl_softerr = 0;
869 clp->cl_rpcclient->cl_softrtry = 0;
870 }
871
872 if (IS_ERR(clp)) {
873 status = PTR_ERR(clp);
874 goto out;
875 }
876
877 smp_wmb();
878 WRITE_ONCE(ds->ds_clp, clp);
879 dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
880 out:
881 return status;
882 }
883
_nfs4_pnfs_v4_ds_connect(struct nfs_server * mds_srv,struct nfs4_pnfs_ds * ds,unsigned int timeo,unsigned int retrans,u32 minor_version,bool tightly_coupled)884 static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
885 struct nfs4_pnfs_ds *ds,
886 unsigned int timeo,
887 unsigned int retrans,
888 u32 minor_version,
889 bool tightly_coupled)
890 {
891 struct nfs_client *clp = ERR_PTR(-EIO);
892 struct nfs_client *mds_clp = mds_srv->nfs_client;
893 enum xprtsec_policies xprtsec_policy = mds_clp->cl_xprtsec.policy;
894 struct nfs4_pnfs_ds_addr *da;
895 int ds_proto;
896 int status = 0;
897
898 dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
899
900 list_for_each_entry(da, &ds->ds_addrs, da_node) {
901 char servername[48];
902
903 dprintk("%s: DS %s: trying address %s\n",
904 __func__, ds->ds_remotestr, da->da_remotestr);
905
906 if (!IS_ERR(clp) && clp->cl_mvops->session_trunk) {
907 struct xprt_create xprt_args = {
908 .ident = da->da_transport,
909 .net = clp->cl_net,
910 .dstaddr = (struct sockaddr *)&da->da_addr,
911 .addrlen = da->da_addrlen,
912 .servername = clp->cl_hostname,
913 .xprtsec = clp->cl_xprtsec,
914 };
915 struct nfs4_add_xprt_data xprtdata = {
916 .clp = clp,
917 };
918 struct rpc_add_xprt_test rpcdata = {
919 .add_xprt_test = clp->cl_mvops->session_trunk,
920 .data = &xprtdata,
921 };
922
923 if (xprt_args.ident == XPRT_TRANSPORT_TCP &&
924 clp->cl_proto == XPRT_TRANSPORT_TCP_TLS) {
925 struct sockaddr *addr =
926 (struct sockaddr *)&da->da_addr;
927 struct sockaddr_in *sin =
928 (struct sockaddr_in *)&da->da_addr;
929 struct sockaddr_in6 *sin6 =
930 (struct sockaddr_in6 *)&da->da_addr;
931
932 /* for NFS with TLS we need to supply a correct
933 * servername of the trunked transport, not the
934 * servername of the main transport stored in
935 * clp->cl_hostname. And set the protocol to
936 * indicate to use TLS
937 */
938 servername[0] = '\0';
939 switch(addr->sa_family) {
940 case AF_INET:
941 snprintf(servername, sizeof(servername),
942 "%pI4", &sin->sin_addr.s_addr);
943 break;
944 case AF_INET6:
945 snprintf(servername, sizeof(servername),
946 "%pI6", &sin6->sin6_addr);
947 break;
948 default:
949 /* do not consider this address */
950 continue;
951 }
952 xprt_args.ident = XPRT_TRANSPORT_TCP_TLS;
953 xprt_args.servername = servername;
954 }
955 if (xprt_args.ident != clp->cl_proto)
956 continue;
957 if (xprt_args.dstaddr->sa_family !=
958 clp->cl_addr.ss_family)
959 continue;
960
961 /**
962 * Test this address for session trunking and
963 * add as an alias
964 */
965 xprtdata.cred = nfs4_get_clid_cred(clp);
966 rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
967 rpc_clnt_setup_test_and_add_xprt,
968 &rpcdata);
969 if (xprtdata.cred)
970 put_cred(xprtdata.cred);
971 } else {
972 ds_proto = da->da_transport;
973 if (ds_proto == XPRT_TRANSPORT_TCP &&
974 xprtsec_policy != RPC_XPRTSEC_NONE)
975 ds_proto = XPRT_TRANSPORT_TCP_TLS;
976
977 clp = nfs4_set_ds_client(mds_srv, &da->da_addr,
978 da->da_addrlen, ds_proto,
979 timeo, retrans, minor_version,
980 tightly_coupled);
981 if (IS_ERR(clp))
982 continue;
983
984 status = nfs4_init_ds_session(clp,
985 mds_srv->nfs_client->cl_lease_time,
986 tightly_coupled);
987 if (status) {
988 nfs_put_client(clp);
989 clp = ERR_PTR(-EIO);
990 continue;
991 }
992 }
993 }
994
995 if (IS_ERR(clp)) {
996 status = PTR_ERR(clp);
997 goto out;
998 }
999
1000 smp_wmb();
1001 WRITE_ONCE(ds->ds_clp, clp);
1002 dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
1003 out:
1004 return status;
1005 }
1006
1007 /*
1008 * Create an rpc connection to the nfs4_pnfs_ds data server.
1009 * Currently only supports IPv4 and IPv6 addresses.
1010 * If connection fails, make devid unavailable and return a -errno.
1011 */
nfs4_pnfs_ds_connect(struct nfs_server * mds_srv,struct nfs4_pnfs_ds * ds,struct nfs4_deviceid_node * devid,unsigned int timeo,unsigned int retrans,u32 version,u32 minor_version,bool tightly_coupled)1012 int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
1013 struct nfs4_deviceid_node *devid, unsigned int timeo,
1014 unsigned int retrans, u32 version, u32 minor_version,
1015 bool tightly_coupled)
1016 {
1017 int err;
1018
1019 do {
1020 err = nfs4_wait_ds_connect(ds);
1021 if (err || ds->ds_clp)
1022 goto out;
1023 if (nfs4_test_deviceid_unavailable(devid)) {
1024 err = -ENODEV;
1025 goto out;
1026 }
1027 } while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);
1028
1029 if (ds->ds_clp)
1030 goto connect_done;
1031
1032 switch (version) {
1033 case 3:
1034 err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, retrans);
1035 break;
1036 case 4:
1037 err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, retrans,
1038 minor_version, tightly_coupled);
1039 break;
1040 default:
1041 dprintk("%s: unsupported DS version %d\n", __func__, version);
1042 err = -EPROTONOSUPPORT;
1043 }
1044
1045 connect_done:
1046 nfs4_clear_ds_conn_bit(ds);
1047 out:
1048 /*
1049 * At this point the ds->ds_clp should be ready, but it might have
1050 * hit an error.
1051 */
1052 if (!err) {
1053 if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
1054 WARN_ON_ONCE(ds->ds_clp ||
1055 !nfs4_test_deviceid_unavailable(devid));
1056 err = -EINVAL;
1057 } else
1058 err = nfs_client_init_status(ds->ds_clp);
1059 }
1060
1061 trace_pnfs_ds_connect(ds->ds_remotestr, err);
1062 return err;
1063 }
1064 EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
1065
1066 /*
1067 * Currently only supports ipv4, ipv6 and one multi-path address.
1068 */
1069 struct nfs4_pnfs_ds_addr *
nfs4_decode_mp_ds_addr(struct net * net,struct xdr_stream * xdr,gfp_t gfp_flags)1070 nfs4_decode_mp_ds_addr(struct net *net, struct xdr_stream *xdr, gfp_t gfp_flags)
1071 {
1072 struct nfs4_pnfs_ds_addr *da = NULL;
1073 char *buf, *portstr;
1074 __be16 port;
1075 ssize_t nlen, rlen;
1076 int tmp[2];
1077 char *netid;
1078 size_t len;
1079 char *startsep = "";
1080 char *endsep = "";
1081
1082
1083 /* r_netid */
1084 nlen = xdr_stream_decode_string_dup(xdr, &netid, XDR_MAX_NETOBJ,
1085 gfp_flags);
1086 if (unlikely(nlen <= 0))
1087 goto out_err;
1088
1089 /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
1090 /* port is ".ABC.DEF", 8 chars max */
1091 rlen = xdr_stream_decode_string_dup(xdr, &buf, INET6_ADDRSTRLEN +
1092 IPV6_SCOPE_ID_LEN + 8, gfp_flags);
1093 if (unlikely(rlen <= 0))
1094 goto out_free_netid;
1095
1096 /* replace port '.' with '-' */
1097 portstr = strrchr(buf, '.');
1098 if (!portstr) {
1099 dprintk("%s: Failed finding expected dot in port\n",
1100 __func__);
1101 goto out_free_buf;
1102 }
1103 *portstr = '-';
1104
1105 /* find '.' between address and port */
1106 portstr = strrchr(buf, '.');
1107 if (!portstr) {
1108 dprintk("%s: Failed finding expected dot between address and "
1109 "port\n", __func__);
1110 goto out_free_buf;
1111 }
1112 *portstr = '\0';
1113
1114 da = nfs4_pnfs_ds_addr_alloc(gfp_flags);
1115 if (unlikely(!da))
1116 goto out_free_buf;
1117
1118 if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
1119 sizeof(da->da_addr))) {
1120 dprintk("%s: error parsing address %s\n", __func__, buf);
1121 goto out_free_da;
1122 }
1123
1124 portstr++;
1125 sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
1126 port = htons((tmp[0] << 8) | (tmp[1]));
1127
1128 switch (da->da_addr.ss_family) {
1129 case AF_INET:
1130 ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
1131 da->da_addrlen = sizeof(struct sockaddr_in);
1132 break;
1133
1134 case AF_INET6:
1135 ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
1136 da->da_addrlen = sizeof(struct sockaddr_in6);
1137 startsep = "[";
1138 endsep = "]";
1139 break;
1140
1141 default:
1142 dprintk("%s: unsupported address family: %u\n",
1143 __func__, da->da_addr.ss_family);
1144 goto out_free_da;
1145 }
1146
1147 da->da_transport = xprt_find_transport_ident(netid);
1148 if (da->da_transport < 0) {
1149 dprintk("%s: ERROR: unknown r_netid \"%s\"\n",
1150 __func__, netid);
1151 goto out_free_da;
1152 }
1153
1154 da->da_netid = netid;
1155
1156 /* save human readable address */
1157 len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
1158 da->da_remotestr = kzalloc(len, gfp_flags);
1159
1160 /* NULL is ok, only used for dprintk */
1161 if (da->da_remotestr)
1162 snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
1163 buf, endsep, ntohs(port));
1164
1165 dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
1166 kfree(buf);
1167 return da;
1168
1169 out_free_da:
1170 kfree(da);
1171 out_free_buf:
1172 dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
1173 kfree(buf);
1174 out_free_netid:
1175 kfree(netid);
1176 out_err:
1177 return NULL;
1178 }
1179 EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr);
1180
1181 void
pnfs_layout_mark_request_commit(struct nfs_page * req,struct pnfs_layout_segment * lseg,struct nfs_commit_info * cinfo,u32 ds_commit_idx)1182 pnfs_layout_mark_request_commit(struct nfs_page *req,
1183 struct pnfs_layout_segment *lseg,
1184 struct nfs_commit_info *cinfo,
1185 u32 ds_commit_idx)
1186 {
1187 struct list_head *list;
1188 struct pnfs_commit_array *array;
1189 struct pnfs_commit_bucket *bucket;
1190
1191 mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
1192 array = pnfs_lookup_commit_array(cinfo->ds, lseg);
1193 if (!array || !pnfs_is_valid_lseg(lseg))
1194 goto out_resched;
1195 bucket = &array->buckets[ds_commit_idx];
1196 list = &bucket->written;
1197 /* Non-empty buckets hold a reference on the lseg. That ref
1198 * is normally transferred to the COMMIT call and released
1199 * there. It could also be released if the last req is pulled
1200 * off due to a rewrite, in which case it will be done in
1201 * pnfs_common_clear_request_commit
1202 */
1203 if (!bucket->lseg)
1204 bucket->lseg = pnfs_get_lseg(lseg);
1205 set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
1206 cinfo->ds->nwritten++;
1207
1208 nfs_request_add_commit_list_locked(req, list, cinfo);
1209 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
1210 nfs_folio_mark_unstable(req, cinfo);
1211 return;
1212 out_resched:
1213 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
1214 cinfo->completion_ops->resched_write(cinfo, req);
1215 }
1216 EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
1217
1218 int
pnfs_nfs_generic_sync(struct inode * inode,bool datasync)1219 pnfs_nfs_generic_sync(struct inode *inode, bool datasync)
1220 {
1221 int ret;
1222
1223 if (!pnfs_layoutcommit_outstanding(inode))
1224 return 0;
1225 ret = nfs_commit_inode(inode, FLUSH_SYNC);
1226 if (ret < 0)
1227 return ret;
1228 if (datasync)
1229 return 0;
1230 return pnfs_layoutcommit_inode(inode, true);
1231 }
1232 EXPORT_SYMBOL_GPL(pnfs_nfs_generic_sync);
1233
1234