]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_bio.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_bio.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95
65 * FreeBSD-Id: nfs_bio.c,v 1.44 1997/09/10 19:52:25 phk Exp $
66 */
1c79356b
A
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/resourcevar.h>
70#include <sys/signalvar.h>
91447636
A
71#include <sys/proc_internal.h>
72#include <sys/kauth.h>
55e303ae 73#include <sys/malloc.h>
1c79356b 74#include <sys/vnode.h>
55e303ae 75#include <sys/dirent.h>
91447636 76#include <sys/mount_internal.h>
1c79356b 77#include <sys/kernel.h>
91447636
A
78#include <sys/ubc_internal.h>
79#include <sys/uio_internal.h>
1c79356b
A
80
81#include <sys/vm.h>
82#include <sys/vmparam.h>
83
84#include <sys/time.h>
85#include <kern/clock.h>
91447636
A
86#include <libkern/OSAtomic.h>
87#include <kern/kalloc.h>
2d21ac55 88#include <kern/thread_call.h>
1c79356b
A
89
90#include <nfs/rpcv2.h>
91#include <nfs/nfsproto.h>
92#include <nfs/nfs.h>
2d21ac55 93#include <nfs/nfs_gss.h>
1c79356b 94#include <nfs/nfsmount.h>
1c79356b 95#include <nfs/nfsnode.h>
91447636 96#include <sys/buf_internal.h>
2d21ac55 97#include <libkern/OSAtomic.h>
1c79356b 98
2d21ac55 99kern_return_t thread_terminate(thread_t); /* XXX */
55e303ae 100
91447636
A
101#define NFSBUFHASH(np, lbn) \
102 (&nfsbufhashtbl[((long)(np) / sizeof(*(np)) + (int)(lbn)) & nfsbufhash])
55e303ae 103LIST_HEAD(nfsbufhashhead, nfsbuf) *nfsbufhashtbl;
483a1d10 104struct nfsbuffreehead nfsbuffree, nfsbuffreemeta, nfsbufdelwri;
55e303ae 105u_long nfsbufhash;
91447636 106int nfsbufcnt, nfsbufmin, nfsbufmax, nfsbufmetacnt, nfsbufmetamax;
483a1d10 107int nfsbuffreecnt, nfsbuffreemetacnt, nfsbufdelwricnt, nfsneedbuffer;
55e303ae 108int nfs_nbdwrite;
2d21ac55
A
109int nfs_buf_timer_on = 0;
110thread_t nfsbufdelwrithd = NULL;
483a1d10 111
91447636 112lck_grp_t *nfs_buf_lck_grp;
91447636
A
113lck_mtx_t *nfs_buf_mutex;
114
2d21ac55 115#define NFSBUF_FREE_PERIOD 30 /* seconds */
483a1d10
A
116#define NFSBUF_LRU_STALE 120
117#define NFSBUF_META_STALE 240
118
119/* number of nfsbufs nfs_buf_freeup() should attempt to free from nfsbuffree list */
120#define LRU_TO_FREEUP 6
121/* number of nfsbufs nfs_buf_freeup() should attempt to free from nfsbuffreemeta list */
122#define META_TO_FREEUP 3
123/* total number of nfsbufs nfs_buf_freeup() should attempt to free */
124#define TOTAL_TO_FREEUP (LRU_TO_FREEUP+META_TO_FREEUP)
2d21ac55 125/* fraction of nfsbufs nfs_buf_freeup() should attempt to free from nfsbuffree list when called from timer */
483a1d10 126#define LRU_FREEUP_FRAC_ON_TIMER 8
2d21ac55 127/* fraction of nfsbufs nfs_buf_freeup() should attempt to free from nfsbuffreemeta list when called from timer */
483a1d10
A
128#define META_FREEUP_FRAC_ON_TIMER 16
129/* fraction of total nfsbufs that nfsbuffreecnt should exceed before bothering to call nfs_buf_freeup() */
130#define LRU_FREEUP_MIN_FRAC 4
131/* fraction of total nfsbufs that nfsbuffreemetacnt should exceed before bothering to call nfs_buf_freeup() */
132#define META_FREEUP_MIN_FRAC 2
55e303ae 133
483a1d10 134#define NFS_BUF_FREEUP() \
91447636 135 do { \
483a1d10
A
136 /* only call nfs_buf_freeup() if it has work to do: */ \
137 if (((nfsbuffreecnt > nfsbufcnt/LRU_FREEUP_MIN_FRAC) || \
138 (nfsbuffreemetacnt > nfsbufcnt/META_FREEUP_MIN_FRAC)) && \
139 ((nfsbufcnt - TOTAL_TO_FREEUP) > nfsbufmin)) \
140 nfs_buf_freeup(0); \
141 } while (0)
55e303ae
A
142
143/*
144 * Initialize nfsbuf lists
145 */
146void
147nfs_nbinit(void)
148{
2d21ac55
A
149 nfs_buf_lck_grp = lck_grp_alloc_init("nfs_buf", LCK_GRP_ATTR_NULL);
150 nfs_buf_mutex = lck_mtx_alloc_init(nfs_buf_lck_grp, LCK_ATTR_NULL);
91447636
A
151
152 nfsbufcnt = nfsbufmetacnt =
153 nfsbuffreecnt = nfsbuffreemetacnt = nfsbufdelwricnt = 0;
154 nfsbufmin = 128;
2d21ac55
A
155 /* size nfsbufmax to cover at most half sane_size (w/default buf size) */
156 nfsbufmax = (sane_size >> PAGE_SHIFT) / (2 * (NFS_RWSIZE >> PAGE_SHIFT));
157 nfsbufmetamax = nfsbufmax / 4;
55e303ae
A
158 nfsneedbuffer = 0;
159 nfs_nbdwrite = 0;
91447636
A
160
161 nfsbufhashtbl = hashinit(nfsbufmax/4, M_TEMP, &nfsbufhash);
162 TAILQ_INIT(&nfsbuffree);
163 TAILQ_INIT(&nfsbuffreemeta);
164 TAILQ_INIT(&nfsbufdelwri);
165
55e303ae
A
166}
167
2d21ac55
A
168/*
169 * Check periodically for stale/unused nfs bufs
170 */
171void
172nfs_buf_timer(__unused void *param0, __unused void *param1)
173{
174 nfs_buf_freeup(1);
175
176 lck_mtx_lock(nfs_buf_mutex);
177 if (nfsbufcnt <= nfsbufmin) {
178 nfs_buf_timer_on = 0;
179 lck_mtx_unlock(nfs_buf_mutex);
180 return;
181 }
182 lck_mtx_unlock(nfs_buf_mutex);
183
184 nfs_interval_timer_start(nfs_buf_timer_call,
185 NFSBUF_FREE_PERIOD * 1000);
186}
187
55e303ae
A
188/*
189 * try to free up some excess, unused nfsbufs
190 */
483a1d10
A
191void
192nfs_buf_freeup(int timer)
55e303ae
A
193{
194 struct nfsbuf *fbp;
483a1d10
A
195 struct timeval now;
196 int count;
91447636
A
197 struct nfsbuffreehead nfsbuffreeup;
198
199 TAILQ_INIT(&nfsbuffreeup);
200
201 lck_mtx_lock(nfs_buf_mutex);
55e303ae 202
483a1d10 203 microuptime(&now);
55e303ae 204
91447636
A
205 FSDBG(320, nfsbufcnt, nfsbuffreecnt, nfsbuffreemetacnt, 0);
206
483a1d10
A
207 count = timer ? nfsbuffreecnt/LRU_FREEUP_FRAC_ON_TIMER : LRU_TO_FREEUP;
208 while ((nfsbufcnt > nfsbufmin) && (count-- > 0)) {
55e303ae
A
209 fbp = TAILQ_FIRST(&nfsbuffree);
210 if (!fbp)
211 break;
91447636
A
212 if (fbp->nb_refs)
213 break;
214 if (NBUFSTAMPVALID(fbp) &&
215 (fbp->nb_timestamp + (2*NFSBUF_LRU_STALE)) > now.tv_sec)
483a1d10
A
216 break;
217 nfs_buf_remfree(fbp);
2d21ac55
A
218 /* disassociate buffer from any nfsnode */
219 if (fbp->nb_np) {
483a1d10
A
220 if (fbp->nb_vnbufs.le_next != NFSNOLIST) {
221 LIST_REMOVE(fbp, nb_vnbufs);
222 fbp->nb_vnbufs.le_next = NFSNOLIST;
223 }
2d21ac55 224 fbp->nb_np = NULL;
483a1d10
A
225 }
226 LIST_REMOVE(fbp, nb_hash);
91447636 227 TAILQ_INSERT_TAIL(&nfsbuffreeup, fbp, nb_free);
483a1d10
A
228 nfsbufcnt--;
229 }
230
231 count = timer ? nfsbuffreemetacnt/META_FREEUP_FRAC_ON_TIMER : META_TO_FREEUP;
232 while ((nfsbufcnt > nfsbufmin) && (count-- > 0)) {
233 fbp = TAILQ_FIRST(&nfsbuffreemeta);
234 if (!fbp)
235 break;
91447636
A
236 if (fbp->nb_refs)
237 break;
238 if (NBUFSTAMPVALID(fbp) &&
239 (fbp->nb_timestamp + (2*NFSBUF_META_STALE)) > now.tv_sec)
483a1d10 240 break;
55e303ae 241 nfs_buf_remfree(fbp);
2d21ac55
A
242 /* disassociate buffer from any nfsnode */
243 if (fbp->nb_np) {
55e303ae
A
244 if (fbp->nb_vnbufs.le_next != NFSNOLIST) {
245 LIST_REMOVE(fbp, nb_vnbufs);
246 fbp->nb_vnbufs.le_next = NFSNOLIST;
247 }
2d21ac55 248 fbp->nb_np = NULL;
55e303ae
A
249 }
250 LIST_REMOVE(fbp, nb_hash);
91447636
A
251 TAILQ_INSERT_TAIL(&nfsbuffreeup, fbp, nb_free);
252 nfsbufcnt--;
253 nfsbufmetacnt--;
254 }
255
256 FSDBG(320, nfsbufcnt, nfsbuffreecnt, nfsbuffreemetacnt, 0);
2d21ac55 257 NFSBUFCNTCHK();
91447636
A
258
259 lck_mtx_unlock(nfs_buf_mutex);
260
261 while ((fbp = TAILQ_FIRST(&nfsbuffreeup))) {
262 TAILQ_REMOVE(&nfsbuffreeup, fbp, nb_free);
55e303ae 263 /* nuke any creds */
2d21ac55 264 if (IS_VALID_CRED(fbp->nb_rcred))
0c530ab8 265 kauth_cred_unref(&fbp->nb_rcred);
2d21ac55 266 if (IS_VALID_CRED(fbp->nb_wcred))
0c530ab8 267 kauth_cred_unref(&fbp->nb_wcred);
91447636
A
268 /* if buf was NB_META, dump buffer */
269 if (ISSET(fbp->nb_flags, NB_META) && fbp->nb_data)
270 kfree(fbp->nb_data, fbp->nb_bufsize);
55e303ae 271 FREE(fbp, M_TEMP);
55e303ae 272 }
91447636 273
55e303ae
A
274}
275
91447636
A
276/*
277 * remove a buffer from the freelist
278 * (must be called with nfs_buf_mutex held)
279 */
55e303ae
A
280void
281nfs_buf_remfree(struct nfsbuf *bp)
282{
283 if (bp->nb_free.tqe_next == NFSNOLIST)
284 panic("nfsbuf not on free list");
285 if (ISSET(bp->nb_flags, NB_DELWRI)) {
286 nfsbufdelwricnt--;
287 TAILQ_REMOVE(&nfsbufdelwri, bp, nb_free);
91447636 288 } else if (ISSET(bp->nb_flags, NB_META)) {
483a1d10
A
289 nfsbuffreemetacnt--;
290 TAILQ_REMOVE(&nfsbuffreemeta, bp, nb_free);
55e303ae
A
291 } else {
292 nfsbuffreecnt--;
293 TAILQ_REMOVE(&nfsbuffree, bp, nb_free);
294 }
295 bp->nb_free.tqe_next = NFSNOLIST;
2d21ac55 296 NFSBUFCNTCHK();
55e303ae
A
297}
298
299/*
300 * check for existence of nfsbuf in cache
301 */
91447636 302boolean_t
2d21ac55 303nfs_buf_is_incore(nfsnode_t np, daddr64_t blkno)
91447636
A
304{
305 boolean_t rv;
306 lck_mtx_lock(nfs_buf_mutex);
2d21ac55 307 if (nfs_buf_incore(np, blkno))
91447636
A
308 rv = TRUE;
309 else
310 rv = FALSE;
311 lck_mtx_unlock(nfs_buf_mutex);
312 return (rv);
313}
314
315/*
316 * return incore buffer (must be called with nfs_buf_mutex held)
317 */
55e303ae 318struct nfsbuf *
2d21ac55 319nfs_buf_incore(nfsnode_t np, daddr64_t blkno)
55e303ae
A
320{
321 /* Search hash chain */
2d21ac55 322 struct nfsbuf * bp = NFSBUFHASH(np, blkno)->lh_first;
55e303ae 323 for (; bp != NULL; bp = bp->nb_hash.le_next)
2d21ac55 324 if ((bp->nb_lblkno == blkno) && (bp->nb_np == np)) {
483a1d10 325 if (!ISSET(bp->nb_flags, NB_INVAL)) {
2d21ac55 326 FSDBG(547, bp, blkno, bp->nb_flags, bp->nb_np);
483a1d10
A
327 return (bp);
328 }
329 }
55e303ae
A
330 return (NULL);
331}
332
333/*
334 * Check if it's OK to drop a page.
335 *
336 * Called by vnode_pager() on pageout request of non-dirty page.
337 * We need to make sure that it's not part of a delayed write.
338 * If it is, we can't let the VM drop it because we may need it
339 * later when/if we need to write the data (again).
340 */
341int
91447636 342nfs_buf_page_inval(vnode_t vp, off_t offset)
55e303ae 343{
2d21ac55 344 struct nfsmount *nmp = VTONMP(vp);
55e303ae 345 struct nfsbuf *bp;
91447636
A
346 int error = 0;
347
2d21ac55
A
348 if (!nmp)
349 return (ENXIO);
350
91447636 351 lck_mtx_lock(nfs_buf_mutex);
2d21ac55 352 bp = nfs_buf_incore(VTONFS(vp), (daddr64_t)(offset / nmp->nm_biosize));
55e303ae 353 if (!bp)
91447636 354 goto out;
55e303ae 355 FSDBG(325, bp, bp->nb_flags, bp->nb_dirtyoff, bp->nb_dirtyend);
91447636
A
356 if (ISSET(bp->nb_lflags, NBL_BUSY)) {
357 error = EBUSY;
358 goto out;
359 }
55e303ae
A
360 /*
361 * If there's a dirty range in the buffer, check to
362 * see if this page intersects with the dirty range.
363 * If it does, we can't let the pager drop the page.
364 */
365 if (bp->nb_dirtyend > 0) {
366 int start = offset - NBOFF(bp);
367 if (bp->nb_dirtyend <= start ||
368 bp->nb_dirtyoff >= (start + PAGE_SIZE))
91447636
A
369 error = 0;
370 else
371 error = EBUSY;
55e303ae 372 }
91447636
A
373out:
374 lck_mtx_unlock(nfs_buf_mutex);
375 return (error);
55e303ae
A
376}
377
91447636
A
378/*
379 * set up the UPL for a buffer
380 * (must NOT be called with nfs_buf_mutex held)
381 */
55e303ae
A
382int
383nfs_buf_upl_setup(struct nfsbuf *bp)
384{
385 kern_return_t kret;
386 upl_t upl;
91447636 387 int upl_flags;
55e303ae
A
388
389 if (ISSET(bp->nb_flags, NB_PAGELIST))
390 return (0);
391
91447636 392 upl_flags = UPL_PRECIOUS;
2d21ac55 393 if (!ISSET(bp->nb_flags, NB_READ)) {
91447636
A
394 /*
395 * We're doing a "write", so we intend to modify
396 * the pages we're gathering.
397 */
398 upl_flags |= UPL_WILL_MODIFY;
399 }
2d21ac55 400 kret = ubc_create_upl(NFSTOV(bp->nb_np), NBOFF(bp), bp->nb_bufsize,
91447636 401 &upl, NULL, upl_flags);
55e303ae
A
402 if (kret == KERN_INVALID_ARGUMENT) {
403 /* vm object probably doesn't exist any more */
404 bp->nb_pagelist = NULL;
405 return (EINVAL);
406 }
407 if (kret != KERN_SUCCESS) {
408 printf("nfs_buf_upl_setup(): failed to get pagelist %d\n", kret);
409 bp->nb_pagelist = NULL;
410 return (EIO);
411 }
412
2d21ac55 413 FSDBG(538, bp, NBOFF(bp), bp->nb_bufsize, bp->nb_np);
55e303ae 414
55e303ae
A
415 bp->nb_pagelist = upl;
416 SET(bp->nb_flags, NB_PAGELIST);
55e303ae
A
417 return (0);
418}
419
91447636
A
420/*
421 * update buffer's valid/dirty info from UBC
422 * (must NOT be called with nfs_buf_mutex held)
423 */
55e303ae
A
424void
425nfs_buf_upl_check(struct nfsbuf *bp)
426{
427 upl_page_info_t *pl;
428 off_t filesize, fileoffset;
429 int i, npages;
430
431 if (!ISSET(bp->nb_flags, NB_PAGELIST))
432 return;
433
434 npages = round_page_32(bp->nb_bufsize) / PAGE_SIZE;
2d21ac55 435 filesize = ubc_getsize(NFSTOV(bp->nb_np));
55e303ae
A
436 fileoffset = NBOFF(bp);
437 if (fileoffset < filesize)
438 SET(bp->nb_flags, NB_CACHE);
439 else
440 CLR(bp->nb_flags, NB_CACHE);
441
442 pl = ubc_upl_pageinfo(bp->nb_pagelist);
443 bp->nb_valid = bp->nb_dirty = 0;
444
445 for (i=0; i < npages; i++, fileoffset += PAGE_SIZE_64) {
446 /* anything beyond the end of the file is not valid or dirty */
447 if (fileoffset >= filesize)
448 break;
449 if (!upl_valid_page(pl, i)) {
450 CLR(bp->nb_flags, NB_CACHE);
451 continue;
452 }
453 NBPGVALID_SET(bp,i);
2d21ac55 454 if (upl_dirty_page(pl, i))
55e303ae 455 NBPGDIRTY_SET(bp, i);
55e303ae
A
456 }
457 fileoffset = NBOFF(bp);
458 if (ISSET(bp->nb_flags, NB_CACHE)) {
459 bp->nb_validoff = 0;
460 bp->nb_validend = bp->nb_bufsize;
461 if (fileoffset + bp->nb_validend > filesize)
462 bp->nb_validend = filesize - fileoffset;
463 } else {
464 bp->nb_validoff = bp->nb_validend = -1;
465 }
466 FSDBG(539, bp, fileoffset, bp->nb_valid, bp->nb_dirty);
467 FSDBG(539, bp->nb_validoff, bp->nb_validend, bp->nb_dirtyoff, bp->nb_dirtyend);
468}
469
91447636
A
470/*
471 * make sure that a buffer is mapped
472 * (must NOT be called with nfs_buf_mutex held)
473 */
2d21ac55 474int
55e303ae
A
475nfs_buf_map(struct nfsbuf *bp)
476{
477 kern_return_t kret;
478
479 if (bp->nb_data)
480 return (0);
481 if (!ISSET(bp->nb_flags, NB_PAGELIST))
482 return (EINVAL);
483
484 kret = ubc_upl_map(bp->nb_pagelist, (vm_address_t *)&(bp->nb_data));
485 if (kret != KERN_SUCCESS)
486 panic("nfs_buf_map: ubc_upl_map() failed with (%d)", kret);
487 if (bp->nb_data == 0)
488 panic("ubc_upl_map mapped 0");
489 FSDBG(540, bp, bp->nb_flags, NBOFF(bp), bp->nb_data);
490 return (0);
491}
492
55e303ae
A
493/*
494 * normalize an nfsbuf's valid range
495 *
496 * the read/write code guarantees that we'll always have a valid
497 * region that is an integral number of pages. If either end
498 * of the valid range isn't page-aligned, it gets corrected
499 * here as we extend the valid range through all of the
500 * contiguous valid pages.
501 */
2d21ac55
A
502void
503nfs_buf_normalize_valid_range(nfsnode_t np, struct nfsbuf *bp)
55e303ae
A
504{
505 int pg, npg;
506 /* pull validoff back to start of contiguous valid page range */
507 pg = bp->nb_validoff/PAGE_SIZE;
508 while (pg >= 0 && NBPGVALID(bp,pg))
509 pg--;
510 bp->nb_validoff = (pg+1) * PAGE_SIZE;
511 /* push validend forward to end of contiguous valid page range */
512 npg = bp->nb_bufsize/PAGE_SIZE;
513 pg = bp->nb_validend/PAGE_SIZE;
514 while (pg < npg && NBPGVALID(bp,pg))
515 pg++;
516 bp->nb_validend = pg * PAGE_SIZE;
517 /* clip to EOF */
91447636 518 if (NBOFF(bp) + bp->nb_validend > (off_t)np->n_size)
55e303ae
A
519 bp->nb_validend = np->n_size % bp->nb_bufsize;
520}
521
522/*
2d21ac55
A
523 * process some entries on the delayed write queue
524 * (must be called with nfs_buf_mutex held)
55e303ae
A
525 */
526static void
2d21ac55 527nfs_buf_delwri_service(void)
55e303ae
A
528{
529 struct nfsbuf *bp;
2d21ac55
A
530 nfsnode_t np;
531 int error, i = 0;
55e303ae 532
55e303ae 533 while (i < 8 && (bp = TAILQ_FIRST(&nfsbufdelwri)) != NULL) {
2d21ac55 534 np = bp->nb_np;
55e303ae 535 nfs_buf_remfree(bp);
91447636
A
536 nfs_buf_refget(bp);
537 while ((error = nfs_buf_acquire(bp, 0, 0, 0)) == EAGAIN);
538 nfs_buf_refrele(bp);
539 if (error)
540 break;
2d21ac55 541 if (!bp->nb_np) {
91447636
A
542 /* buffer is no longer valid */
543 nfs_buf_drop(bp);
544 continue;
545 }
8f6c56a5
A
546 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT))
547 nfs_buf_check_write_verifier(np, bp);
55e303ae
A
548 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
549 /* put buffer at end of delwri list */
550 TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free);
551 nfsbufdelwricnt++;
91447636
A
552 nfs_buf_drop(bp);
553 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 554 nfs_flushcommits(np, 1);
55e303ae 555 } else {
91447636
A
556 SET(bp->nb_flags, NB_ASYNC);
557 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
558 nfs_buf_write(bp);
559 }
560 i++;
91447636 561 lck_mtx_lock(nfs_buf_mutex);
55e303ae 562 }
2d21ac55
A
563}
564
565/*
566 * thread to service the delayed write queue when asked
567 */
568static void
569nfs_buf_delwri_thread(__unused void *arg, __unused wait_result_t wr)
570{
571 struct timespec ts = { 30, 0 };
572 int error = 0;
573
574 lck_mtx_lock(nfs_buf_mutex);
575 while (!error) {
576 nfs_buf_delwri_service();
577 error = msleep(&nfsbufdelwrithd, nfs_buf_mutex, 0, "nfsbufdelwri", &ts);
578 }
579 nfsbufdelwrithd = NULL;
580 lck_mtx_unlock(nfs_buf_mutex);
581 thread_terminate(nfsbufdelwrithd);
582}
583
584/*
585 * try to push out some delayed/uncommitted writes
586 * ("locked" indicates whether nfs_buf_mutex is already held)
587 */
588static void
589nfs_buf_delwri_push(int locked)
590{
591 if (TAILQ_EMPTY(&nfsbufdelwri))
592 return;
593 if (!locked)
594 lck_mtx_lock(nfs_buf_mutex);
595 /* wake up the delayed write service thread */
596 if (nfsbufdelwrithd)
597 wakeup(&nfsbufdelwrithd);
598 else if (kernel_thread_start(nfs_buf_delwri_thread, NULL, &nfsbufdelwrithd) == KERN_SUCCESS)
599 thread_deallocate(nfsbufdelwrithd);
600 /* otherwise, try to do some of the work ourselves */
601 if (!nfsbufdelwrithd)
602 nfs_buf_delwri_service();
91447636
A
603 if (!locked)
604 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
605}
606
607/*
91447636
A
608 * Get an nfs buffer.
609 *
610 * Returns errno on error, 0 otherwise.
611 * Any buffer is returned in *bpp.
612 *
613 * If NBLK_ONLYVALID is set, only return buffer if found in cache.
614 * If NBLK_NOWAIT is set, don't wait for the buffer if it's marked BUSY.
615 *
616 * Check for existence of buffer in cache.
617 * Or attempt to reuse a buffer from one of the free lists.
618 * Or allocate a new buffer if we haven't already hit max allocation.
619 * Or wait for a free buffer.
620 *
621 * If available buffer found, prepare it, and return it.
622 *
623 * If the calling process is interrupted by a signal for
624 * an interruptible mount point, return EINTR.
55e303ae 625 */
91447636 626int
55e303ae 627nfs_buf_get(
2d21ac55 628 nfsnode_t np,
91447636 629 daddr64_t blkno,
55e303ae 630 int size,
2d21ac55 631 thread_t thd,
91447636
A
632 int flags,
633 struct nfsbuf **bpp)
55e303ae 634{
2d21ac55
A
635 vnode_t vp = NFSTOV(np);
636 struct nfsmount *nmp = VTONMP(vp);
55e303ae 637 struct nfsbuf *bp;
2d21ac55 638 int bufsize;
55e303ae 639 int slpflag = PCATCH;
91447636
A
640 int operation = (flags & NBLK_OPMASK);
641 int error = 0;
642 struct timespec ts;
55e303ae 643
2d21ac55 644 FSDBG_TOP(541, np, blkno, size, flags);
91447636 645 *bpp = NULL;
55e303ae
A
646
647 bufsize = size;
0c530ab8
A
648 if (bufsize > NFS_MAXBSIZE)
649 panic("nfs_buf_get: buffer larger than NFS_MAXBSIZE requested");
55e303ae 650
0c530ab8 651 if (!nmp) {
2d21ac55 652 FSDBG_BOT(541, np, blkno, 0, ENXIO);
0c530ab8
A
653 return (ENXIO);
654 }
55e303ae 655
2d21ac55 656 if (!UBCINFOEXISTS(vp)) {
91447636 657 operation = NBLK_META;
2d21ac55 658 } else if (bufsize < nmp->nm_biosize) {
55e303ae 659 /* reg files should always have biosize blocks */
2d21ac55 660 bufsize = nmp->nm_biosize;
91447636 661 }
55e303ae 662
91447636 663 /* if NBLK_WRITE, check for too many delayed/uncommitted writes */
2d21ac55
A
664 if ((operation == NBLK_WRITE) && (nfs_nbdwrite > NFS_A_LOT_OF_DELAYED_WRITES)) {
665 FSDBG_TOP(542, np, blkno, nfs_nbdwrite, NFS_A_LOT_OF_DELAYED_WRITES);
55e303ae
A
666
667 /* poke the delwri list */
91447636 668 nfs_buf_delwri_push(0);
55e303ae
A
669
670 /* sleep to let other threads run... */
671 tsleep(&nfs_nbdwrite, PCATCH, "nfs_nbdwrite", 1);
2d21ac55 672 FSDBG_BOT(542, np, blkno, nfs_nbdwrite, NFS_A_LOT_OF_DELAYED_WRITES);
55e303ae
A
673 }
674
675loop:
91447636 676 lck_mtx_lock(nfs_buf_mutex);
55e303ae
A
677
678 /* check for existence of nfsbuf in cache */
2d21ac55 679 if ((bp = nfs_buf_incore(np, blkno))) {
55e303ae 680 /* if busy, set wanted and wait */
91447636
A
681 if (ISSET(bp->nb_lflags, NBL_BUSY)) {
682 if (flags & NBLK_NOWAIT) {
683 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 684 FSDBG_BOT(541, np, blkno, bp, 0xbcbcbcbc);
91447636
A
685 return (0);
686 }
2d21ac55 687 FSDBG_TOP(543, np, blkno, bp, bp->nb_flags);
91447636
A
688 SET(bp->nb_lflags, NBL_WANTED);
689
690 ts.tv_sec = 2;
691 ts.tv_nsec = 0;
2d21ac55
A
692 error = msleep(bp, nfs_buf_mutex, slpflag|(PRIBIO+1)|PDROP,
693 "nfsbufget", (slpflag == PCATCH) ? NULL : &ts);
694 if (error == EWOULDBLOCK)
695 error = 0;
55e303ae 696 slpflag = 0;
2d21ac55
A
697 FSDBG_BOT(543, np, blkno, bp, bp->nb_flags);
698 if (error || ((error = nfs_sigintr(VTONMP(vp), NULL, thd, 0)))) {
699 FSDBG_BOT(541, np, blkno, 0, error);
91447636 700 return (error);
55e303ae
A
701 }
702 goto loop;
703 }
704 if (bp->nb_bufsize != bufsize)
705 panic("nfsbuf size mismatch");
91447636
A
706 SET(bp->nb_lflags, NBL_BUSY);
707 SET(bp->nb_flags, NB_CACHE);
55e303ae
A
708 nfs_buf_remfree(bp);
709 /* additional paranoia: */
710 if (ISSET(bp->nb_flags, NB_PAGELIST))
711 panic("pagelist buffer was not busy");
712 goto buffer_setup;
713 }
714
91447636
A
715 if (flags & NBLK_ONLYVALID) {
716 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 717 FSDBG_BOT(541, np, blkno, 0, 0x0000cace);
91447636
A
718 return (0);
719 }
720
55e303ae
A
721 /*
722 * where to get a free buffer:
91447636 723 * - if meta and maxmeta reached, must reuse meta
55e303ae 724 * - alloc new if we haven't reached min bufs
483a1d10
A
725 * - if free lists are NOT empty
726 * - if free list is stale, use it
727 * - else if freemeta list is stale, use it
728 * - else if max bufs allocated, use least-time-to-stale
55e303ae
A
729 * - alloc new if we haven't reached max allowed
730 * - start clearing out delwri list and try again
731 */
732
91447636
A
733 if ((operation == NBLK_META) && (nfsbufmetacnt >= nfsbufmetamax)) {
734 /* if we've hit max meta buffers, must reuse a meta buffer */
735 bp = TAILQ_FIRST(&nfsbuffreemeta);
736 } else if ((nfsbufcnt > nfsbufmin) &&
483a1d10
A
737 (!TAILQ_EMPTY(&nfsbuffree) || !TAILQ_EMPTY(&nfsbuffreemeta))) {
738 /* try to pull an nfsbuf off a free list */
739 struct nfsbuf *lrubp, *metabp;
740 struct timeval now;
741 microuptime(&now);
742
91447636 743 /* if the next LRU or META buffer is invalid or stale, use it */
483a1d10 744 lrubp = TAILQ_FIRST(&nfsbuffree);
91447636
A
745 if (lrubp && (!NBUFSTAMPVALID(lrubp) ||
746 ((lrubp->nb_timestamp + NFSBUF_LRU_STALE) < now.tv_sec)))
483a1d10
A
747 bp = lrubp;
748 metabp = TAILQ_FIRST(&nfsbuffreemeta);
91447636
A
749 if (!bp && metabp && (!NBUFSTAMPVALID(metabp) ||
750 ((metabp->nb_timestamp + NFSBUF_META_STALE) < now.tv_sec)))
483a1d10
A
751 bp = metabp;
752
753 if (!bp && (nfsbufcnt >= nfsbufmax)) {
754 /* we've already allocated all bufs, so */
755 /* choose the buffer that'll go stale first */
756 if (!metabp)
757 bp = lrubp;
758 else if (!lrubp)
759 bp = metabp;
760 else {
761 int32_t lru_stale_time, meta_stale_time;
762 lru_stale_time = lrubp->nb_timestamp + NFSBUF_LRU_STALE;
763 meta_stale_time = metabp->nb_timestamp + NFSBUF_META_STALE;
764 if (lru_stale_time <= meta_stale_time)
765 bp = lrubp;
766 else
767 bp = metabp;
55e303ae 768 }
55e303ae 769 }
91447636 770 }
483a1d10 771
91447636
A
772 if (bp) {
773 /* we have a buffer to reuse */
2d21ac55 774 FSDBG(544, np, blkno, bp, bp->nb_flags);
91447636
A
775 nfs_buf_remfree(bp);
776 if (ISSET(bp->nb_flags, NB_DELWRI))
777 panic("nfs_buf_get: delwri");
778 SET(bp->nb_lflags, NBL_BUSY);
2d21ac55
A
779 /* disassociate buffer from previous nfsnode */
780 if (bp->nb_np) {
91447636
A
781 if (bp->nb_vnbufs.le_next != NFSNOLIST) {
782 LIST_REMOVE(bp, nb_vnbufs);
783 bp->nb_vnbufs.le_next = NFSNOLIST;
483a1d10 784 }
2d21ac55 785 bp->nb_np = NULL;
91447636
A
786 }
787 LIST_REMOVE(bp, nb_hash);
788 /* nuke any creds we're holding */
2d21ac55 789 if (IS_VALID_CRED(bp->nb_rcred))
0c530ab8 790 kauth_cred_unref(&bp->nb_rcred);
2d21ac55 791 if (IS_VALID_CRED(bp->nb_wcred))
0c530ab8 792 kauth_cred_unref(&bp->nb_wcred);
91447636
A
793 /* if buf will no longer be NB_META, dump old buffer */
794 if (operation == NBLK_META) {
795 if (!ISSET(bp->nb_flags, NB_META))
796 nfsbufmetacnt++;
797 } else if (ISSET(bp->nb_flags, NB_META)) {
798 if (bp->nb_data) {
799 kfree(bp->nb_data, bp->nb_bufsize);
483a1d10
A
800 bp->nb_data = NULL;
801 }
91447636 802 nfsbufmetacnt--;
55e303ae 803 }
91447636
A
804 /* re-init buf fields */
805 bp->nb_error = 0;
806 bp->nb_validoff = bp->nb_validend = -1;
807 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
808 bp->nb_valid = 0;
809 bp->nb_dirty = 0;
8f6c56a5 810 bp->nb_verf = 0;
91447636
A
811 } else {
812 /* no buffer to reuse */
813 if ((nfsbufcnt < nfsbufmax) &&
814 ((operation != NBLK_META) || (nfsbufmetacnt < nfsbufmetamax))) {
483a1d10
A
815 /* just alloc a new one */
816 MALLOC(bp, struct nfsbuf *, sizeof(struct nfsbuf), M_TEMP, M_WAITOK);
91447636
A
817 if (!bp) {
818 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 819 FSDBG_BOT(541, np, blkno, 0, error);
91447636
A
820 return (ENOMEM);
821 }
483a1d10 822 nfsbufcnt++;
2d21ac55
A
823
824 /*
825 * If any excess bufs, make sure the timer
826 * is running to free them up later.
827 */
828 if (nfsbufcnt > nfsbufmin && !nfs_buf_timer_on) {
829 nfs_buf_timer_on = 1;
830 nfs_interval_timer_start(nfs_buf_timer_call,
831 NFSBUF_FREE_PERIOD * 1000);
832 }
833
91447636
A
834 if (operation == NBLK_META)
835 nfsbufmetacnt++;
2d21ac55 836 NFSBUFCNTCHK();
483a1d10
A
837 /* init nfsbuf */
838 bzero(bp, sizeof(*bp));
839 bp->nb_free.tqe_next = NFSNOLIST;
840 bp->nb_validoff = bp->nb_validend = -1;
2d21ac55 841 FSDBG(545, np, blkno, bp, 0);
483a1d10
A
842 } else {
843 /* too many bufs... wait for buffers to free up */
2d21ac55 844 FSDBG_TOP(546, np, blkno, nfsbufcnt, nfsbufmax);
55e303ae 845
483a1d10 846 /* poke the delwri list */
91447636 847 nfs_buf_delwri_push(1);
483a1d10
A
848
849 nfsneedbuffer = 1;
2d21ac55
A
850 error = msleep(&nfsneedbuffer, nfs_buf_mutex, PCATCH|PDROP, "nfsbufget", NULL);
851 FSDBG_BOT(546, np, blkno, nfsbufcnt, nfsbufmax);
852 if (error || ((error = nfs_sigintr(VTONMP(vp), NULL, thd, 0)))) {
853 FSDBG_BOT(541, np, blkno, 0, error);
91447636 854 return (error);
483a1d10
A
855 }
856 goto loop;
55e303ae 857 }
55e303ae
A
858 }
859
55e303ae 860 /* setup nfsbuf */
91447636
A
861 bp->nb_lflags = NBL_BUSY;
862 bp->nb_flags = 0;
55e303ae
A
863 bp->nb_lblkno = blkno;
864 /* insert buf in hash */
91447636 865 LIST_INSERT_HEAD(NFSBUFHASH(np, blkno), bp, nb_hash);
2d21ac55
A
866 /* associate buffer with new nfsnode */
867 bp->nb_np = np;
55e303ae
A
868 LIST_INSERT_HEAD(&np->n_cleanblkhd, bp, nb_vnbufs);
869
870buffer_setup:
871
91447636
A
872 /* unlock hash */
873 lck_mtx_unlock(nfs_buf_mutex);
874
55e303ae 875 switch (operation) {
91447636 876 case NBLK_META:
55e303ae
A
877 SET(bp->nb_flags, NB_META);
878 if ((bp->nb_bufsize != bufsize) && bp->nb_data) {
91447636 879 kfree(bp->nb_data, bp->nb_bufsize);
55e303ae
A
880 bp->nb_data = NULL;
881 bp->nb_validoff = bp->nb_validend = -1;
882 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
883 bp->nb_valid = 0;
884 bp->nb_dirty = 0;
885 CLR(bp->nb_flags, NB_CACHE);
886 }
887 if (!bp->nb_data)
91447636
A
888 bp->nb_data = kalloc(bufsize);
889 if (!bp->nb_data) {
890 /* Ack! couldn't allocate the data buffer! */
2d21ac55 891 /* clean up buffer and return error */
91447636
A
892 lck_mtx_lock(nfs_buf_mutex);
893 LIST_REMOVE(bp, nb_vnbufs);
894 bp->nb_vnbufs.le_next = NFSNOLIST;
2d21ac55 895 bp->nb_np = NULL;
91447636
A
896 /* invalidate usage timestamp to allow immediate freeing */
897 NBUFSTAMPINVALIDATE(bp);
898 if (bp->nb_free.tqe_next != NFSNOLIST)
899 panic("nfsbuf on freelist");
900 TAILQ_INSERT_HEAD(&nfsbuffree, bp, nb_free);
901 nfsbuffreecnt++;
902 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 903 FSDBG_BOT(541, np, blkno, 0xb00, ENOMEM);
91447636
A
904 return (ENOMEM);
905 }
55e303ae
A
906 bp->nb_bufsize = bufsize;
907 break;
908
91447636
A
909 case NBLK_READ:
910 case NBLK_WRITE:
911 /*
912 * Set or clear NB_READ now to let the UPL subsystem know
913 * if we intend to modify the pages or not.
914 */
915 if (operation == NBLK_READ) {
916 SET(bp->nb_flags, NB_READ);
917 } else {
918 CLR(bp->nb_flags, NB_READ);
919 }
55e303ae
A
920 if (bufsize < PAGE_SIZE)
921 bufsize = PAGE_SIZE;
922 bp->nb_bufsize = bufsize;
923 bp->nb_validoff = bp->nb_validend = -1;
924
91447636 925 if (UBCINFOEXISTS(vp)) {
2d21ac55 926 /* set up upl */
55e303ae
A
927 if (nfs_buf_upl_setup(bp)) {
928 /* unable to create upl */
929 /* vm object must no longer exist */
2d21ac55 930 /* clean up buffer and return error */
91447636 931 lck_mtx_lock(nfs_buf_mutex);
55e303ae
A
932 LIST_REMOVE(bp, nb_vnbufs);
933 bp->nb_vnbufs.le_next = NFSNOLIST;
2d21ac55 934 bp->nb_np = NULL;
91447636
A
935 /* invalidate usage timestamp to allow immediate freeing */
936 NBUFSTAMPINVALIDATE(bp);
55e303ae
A
937 if (bp->nb_free.tqe_next != NFSNOLIST)
938 panic("nfsbuf on freelist");
939 TAILQ_INSERT_HEAD(&nfsbuffree, bp, nb_free);
940 nfsbuffreecnt++;
91447636 941 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 942 FSDBG_BOT(541, np, blkno, 0x2bc, EIO);
91447636 943 return (EIO);
55e303ae
A
944 }
945 nfs_buf_upl_check(bp);
946 }
947 break;
948
949 default:
950 panic("nfs_buf_get: %d unknown operation", operation);
951 }
952
91447636 953 *bpp = bp;
55e303ae 954
2d21ac55 955 FSDBG_BOT(541, np, blkno, bp, bp->nb_flags);
55e303ae 956
91447636 957 return (0);
55e303ae
A
958}
959
960void
483a1d10 961nfs_buf_release(struct nfsbuf *bp, int freeup)
55e303ae 962{
2d21ac55
A
963 nfsnode_t np = bp->nb_np;
964 vnode_t vp;
483a1d10 965 struct timeval now;
91447636 966 int wakeup_needbuffer, wakeup_buffer, wakeup_nbdwrite;
55e303ae
A
967
968 FSDBG_TOP(548, bp, NBOFF(bp), bp->nb_flags, bp->nb_data);
969 FSDBG(548, bp->nb_validoff, bp->nb_validend, bp->nb_dirtyoff, bp->nb_dirtyend);
970 FSDBG(548, bp->nb_valid, 0, bp->nb_dirty, 0);
971
2d21ac55
A
972 vp = np ? NFSTOV(np) : NULL;
973 if (vp && UBCINFOEXISTS(vp) && bp->nb_bufsize) {
55e303ae
A
974 int upl_flags;
975 upl_t upl;
976 int i, rv;
977
978 if (!ISSET(bp->nb_flags, NB_PAGELIST) && !ISSET(bp->nb_flags, NB_INVAL)) {
979 rv = nfs_buf_upl_setup(bp);
980 if (rv)
981 printf("nfs_buf_release: upl create failed %d\n", rv);
982 else
983 nfs_buf_upl_check(bp);
984 }
985 upl = bp->nb_pagelist;
986 if (!upl)
987 goto pagelist_cleanup_done;
988 if (bp->nb_data) {
989 if (ubc_upl_unmap(upl) != KERN_SUCCESS)
990 panic("ubc_upl_unmap failed");
991 bp->nb_data = NULL;
992 }
2d21ac55
A
993 /*
994 * Abort the pages on error or: if this is an invalid or
995 * non-needcommit nocache buffer AND no pages are dirty.
996 */
997 if (ISSET(bp->nb_flags, NB_ERROR) || (!bp->nb_dirty && (ISSET(bp->nb_flags, NB_INVAL) ||
998 (ISSET(bp->nb_flags, NB_NOCACHE) && !ISSET(bp->nb_flags, (NB_NEEDCOMMIT | NB_DELWRI)))))) {
999 if (ISSET(bp->nb_flags, (NB_READ | NB_INVAL | NB_NOCACHE)))
55e303ae
A
1000 upl_flags = UPL_ABORT_DUMP_PAGES;
1001 else
1002 upl_flags = 0;
1003 ubc_upl_abort(upl, upl_flags);
1004 goto pagelist_cleanup_done;
1005 }
1006 for (i=0; i <= (bp->nb_bufsize - 1)/PAGE_SIZE; i++) {
1007 if (!NBPGVALID(bp,i))
1008 ubc_upl_abort_range(upl,
1009 i*PAGE_SIZE, PAGE_SIZE,
1010 UPL_ABORT_DUMP_PAGES |
1011 UPL_ABORT_FREE_ON_EMPTY);
1012 else {
1013 if (NBPGDIRTY(bp,i))
1014 upl_flags = UPL_COMMIT_SET_DIRTY;
1015 else
1016 upl_flags = UPL_COMMIT_CLEAR_DIRTY;
1017 ubc_upl_commit_range(upl,
1018 i*PAGE_SIZE, PAGE_SIZE,
1019 upl_flags |
1020 UPL_COMMIT_INACTIVATE |
1021 UPL_COMMIT_FREE_ON_EMPTY);
1022 }
1023 }
1024pagelist_cleanup_done:
1025 /* was this the last buffer in the file? */
2d21ac55 1026 if (NBOFF(bp) + bp->nb_bufsize > (off_t)(np->n_size)) {
55e303ae 1027 /* if so, invalidate all pages of last buffer past EOF */
91447636 1028 off_t start, end;
2d21ac55 1029 start = trunc_page_64(np->n_size) + PAGE_SIZE_64;
0c530ab8 1030 end = trunc_page_64(NBOFF(bp) + bp->nb_bufsize);
91447636
A
1031 if (end > start) {
1032 if (!(rv = ubc_sync_range(vp, start, end, UBC_INVALIDATE)))
1033 printf("nfs_buf_release(): ubc_sync_range failed!\n");
1034 }
55e303ae
A
1035 }
1036 CLR(bp->nb_flags, NB_PAGELIST);
1037 bp->nb_pagelist = NULL;
1038 }
1039
91447636
A
1040 lck_mtx_lock(nfs_buf_mutex);
1041
1042 wakeup_needbuffer = wakeup_buffer = wakeup_nbdwrite = 0;
1043
55e303ae
A
1044 /* Wake up any processes waiting for any buffer to become free. */
1045 if (nfsneedbuffer) {
1046 nfsneedbuffer = 0;
91447636 1047 wakeup_needbuffer = 1;
55e303ae
A
1048 }
1049 /* Wake up any processes waiting for _this_ buffer to become free. */
91447636
A
1050 if (ISSET(bp->nb_lflags, NBL_WANTED)) {
1051 CLR(bp->nb_lflags, NBL_WANTED);
1052 wakeup_buffer = 1;
55e303ae
A
1053 }
1054
0c530ab8
A
1055 /* If it's non-needcommit nocache, or an error, mark it invalid. */
1056 if (ISSET(bp->nb_flags, NB_ERROR) ||
1057 (ISSET(bp->nb_flags, NB_NOCACHE) && !ISSET(bp->nb_flags, (NB_NEEDCOMMIT | NB_DELWRI))))
55e303ae
A
1058 SET(bp->nb_flags, NB_INVAL);
1059
1060 if ((bp->nb_bufsize <= 0) || ISSET(bp->nb_flags, NB_INVAL)) {
2d21ac55 1061 /* If it's invalid or empty, dissociate it from its nfsnode */
55e303ae
A
1062 if (bp->nb_vnbufs.le_next != NFSNOLIST) {
1063 LIST_REMOVE(bp, nb_vnbufs);
1064 bp->nb_vnbufs.le_next = NFSNOLIST;
1065 }
2d21ac55 1066 bp->nb_np = NULL;
55e303ae
A
1067 /* if this was a delayed write, wakeup anyone */
1068 /* waiting for delayed writes to complete */
1069 if (ISSET(bp->nb_flags, NB_DELWRI)) {
1070 CLR(bp->nb_flags, NB_DELWRI);
2d21ac55
A
1071 nfs_nbdwrite--;
1072 NFSBUFCNTCHK();
91447636 1073 wakeup_nbdwrite = 1;
55e303ae 1074 }
91447636
A
1075 /* invalidate usage timestamp to allow immediate freeing */
1076 NBUFSTAMPINVALIDATE(bp);
55e303ae
A
1077 /* put buffer at head of free list */
1078 if (bp->nb_free.tqe_next != NFSNOLIST)
1079 panic("nfsbuf on freelist");
483a1d10 1080 SET(bp->nb_flags, NB_INVAL);
91447636
A
1081 if (ISSET(bp->nb_flags, NB_META)) {
1082 TAILQ_INSERT_HEAD(&nfsbuffreemeta, bp, nb_free);
1083 nfsbuffreemetacnt++;
1084 } else {
1085 TAILQ_INSERT_HEAD(&nfsbuffree, bp, nb_free);
1086 nfsbuffreecnt++;
1087 }
55e303ae
A
1088 } else if (ISSET(bp->nb_flags, NB_DELWRI)) {
1089 /* put buffer at end of delwri list */
1090 if (bp->nb_free.tqe_next != NFSNOLIST)
1091 panic("nfsbuf on freelist");
1092 TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free);
1093 nfsbufdelwricnt++;
91447636 1094 freeup = 0;
55e303ae 1095 } else {
483a1d10
A
1096 /* update usage timestamp */
1097 microuptime(&now);
1098 bp->nb_timestamp = now.tv_sec;
55e303ae
A
1099 /* put buffer at end of free list */
1100 if (bp->nb_free.tqe_next != NFSNOLIST)
1101 panic("nfsbuf on freelist");
483a1d10
A
1102 if (ISSET(bp->nb_flags, NB_META)) {
1103 TAILQ_INSERT_TAIL(&nfsbuffreemeta, bp, nb_free);
1104 nfsbuffreemetacnt++;
1105 } else {
1106 TAILQ_INSERT_TAIL(&nfsbuffree, bp, nb_free);
1107 nfsbuffreecnt++;
1108 }
55e303ae
A
1109 }
1110
2d21ac55 1111 NFSBUFCNTCHK();
55e303ae
A
1112
1113 /* Unlock the buffer. */
2d21ac55 1114 CLR(bp->nb_flags, (NB_ASYNC | NB_STABLE));
91447636 1115 CLR(bp->nb_lflags, NBL_BUSY);
55e303ae
A
1116
1117 FSDBG_BOT(548, bp, NBOFF(bp), bp->nb_flags, bp->nb_data);
91447636
A
1118
1119 lck_mtx_unlock(nfs_buf_mutex);
1120
1121 if (wakeup_needbuffer)
1122 wakeup(&nfsneedbuffer);
1123 if (wakeup_buffer)
1124 wakeup(bp);
1125 if (wakeup_nbdwrite)
1126 wakeup(&nfs_nbdwrite);
1127 if (freeup)
1128 NFS_BUF_FREEUP();
55e303ae
A
1129}
1130
1131/*
1132 * Wait for operations on the buffer to complete.
1133 * When they do, extract and return the I/O's error value.
1134 */
1135int
1136nfs_buf_iowait(struct nfsbuf *bp)
1137{
1138 FSDBG_TOP(549, bp, NBOFF(bp), bp->nb_flags, bp->nb_error);
1139
91447636
A
1140 lck_mtx_lock(nfs_buf_mutex);
1141
55e303ae 1142 while (!ISSET(bp->nb_flags, NB_DONE))
2d21ac55 1143 msleep(bp, nfs_buf_mutex, PRIBIO + 1, "nfs_buf_iowait", NULL);
91447636
A
1144
1145 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
1146
1147 FSDBG_BOT(549, bp, NBOFF(bp), bp->nb_flags, bp->nb_error);
1148
1149 /* check for interruption of I/O, then errors. */
1150 if (ISSET(bp->nb_flags, NB_EINTR)) {
1151 CLR(bp->nb_flags, NB_EINTR);
1152 return (EINTR);
1153 } else if (ISSET(bp->nb_flags, NB_ERROR))
1154 return (bp->nb_error ? bp->nb_error : EIO);
1155 return (0);
1156}
1157
1158/*
1159 * Mark I/O complete on a buffer.
1160 */
1161void
1162nfs_buf_iodone(struct nfsbuf *bp)
1163{
55e303ae
A
1164
1165 FSDBG_TOP(550, bp, NBOFF(bp), bp->nb_flags, bp->nb_error);
1166
1167 if (ISSET(bp->nb_flags, NB_DONE))
1168 panic("nfs_buf_iodone already");
55e303ae
A
1169
1170 if (!ISSET(bp->nb_flags, NB_READ)) {
1171 CLR(bp->nb_flags, NB_WRITEINPROG);
91447636
A
1172 /*
1173 * vnode_writedone() takes care of waking up
1174 * any throttled write operations
1175 */
2d21ac55 1176 vnode_writedone(NFSTOV(bp->nb_np));
55e303ae 1177 }
91447636
A
1178 if (ISSET(bp->nb_flags, NB_ASYNC)) { /* if async, release it */
1179 SET(bp->nb_flags, NB_DONE); /* note that it's done */
483a1d10 1180 nfs_buf_release(bp, 1);
91447636
A
1181 } else { /* or just wakeup the buffer */
1182 lck_mtx_lock(nfs_buf_mutex);
1183 SET(bp->nb_flags, NB_DONE); /* note that it's done */
1184 CLR(bp->nb_lflags, NBL_WANTED);
1185 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
1186 wakeup(bp);
1187 }
1188
1189 FSDBG_BOT(550, bp, NBOFF(bp), bp->nb_flags, bp->nb_error);
1190}
1191
1192void
2d21ac55 1193nfs_buf_write_delayed(struct nfsbuf *bp)
55e303ae 1194{
2d21ac55 1195 nfsnode_t np = bp->nb_np;
55e303ae
A
1196
1197 FSDBG_TOP(551, bp, NBOFF(bp), bp->nb_flags, 0);
1198 FSDBG(551, bp, bp->nb_dirtyoff, bp->nb_dirtyend, bp->nb_dirty);
1199
1200 /*
1201 * If the block hasn't been seen before:
1202 * (1) Mark it as having been seen,
2d21ac55 1203 * (2) Make sure it's on its node's correct block list,
55e303ae
A
1204 */
1205 if (!ISSET(bp->nb_flags, NB_DELWRI)) {
1206 SET(bp->nb_flags, NB_DELWRI);
55e303ae 1207 /* move to dirty list */
91447636 1208 lck_mtx_lock(nfs_buf_mutex);
2d21ac55
A
1209 nfs_nbdwrite++;
1210 NFSBUFCNTCHK();
55e303ae
A
1211 if (bp->nb_vnbufs.le_next != NFSNOLIST)
1212 LIST_REMOVE(bp, nb_vnbufs);
2d21ac55 1213 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
91447636 1214 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
1215 }
1216
1217 /*
1218 * If the vnode has "too many" write operations in progress
1219 * wait for them to finish the IO
1220 */
2d21ac55
A
1221 vnode_waitforwrites(NFSTOV(np), VNODE_ASYNC_THROTTLE, 0, 0, "nfs_buf_write_delayed");
1222
1223 /* the file is in a modified state, so make sure the flag's set */
1224 nfs_lock(np, NFS_NODE_LOCK_FORCE);
1225 np->n_flag |= NMODIFIED;
1226 nfs_unlock(np);
55e303ae
A
1227
1228 /*
2d21ac55
A
1229 * If we have too many delayed write buffers,
1230 * just fall back to doing the async write.
55e303ae
A
1231 */
1232 if (nfs_nbdwrite < 0)
1233 panic("nfs_buf_write_delayed: Negative nfs_nbdwrite");
2d21ac55 1234 if (nfs_nbdwrite > NFS_A_LOT_OF_DELAYED_WRITES) {
55e303ae
A
1235 /* issue async write */
1236 SET(bp->nb_flags, NB_ASYNC);
1237 nfs_buf_write(bp);
1238 FSDBG_BOT(551, bp, NBOFF(bp), bp->nb_flags, bp->nb_error);
1239 return;
1240 }
2d21ac55 1241
55e303ae
A
1242 /* Otherwise, the "write" is done, so mark and release the buffer. */
1243 SET(bp->nb_flags, NB_DONE);
483a1d10 1244 nfs_buf_release(bp, 1);
55e303ae
A
1245 FSDBG_BOT(551, bp, NBOFF(bp), bp->nb_flags, 0);
1246 return;
1247}
1248
8f6c56a5
A
1249/*
1250 * Check that a "needcommit" buffer can still be committed.
1251 * If the write verifier has changed, we need to clear the
1252 * the needcommit flag.
1253 */
1254void
2d21ac55 1255nfs_buf_check_write_verifier(nfsnode_t np, struct nfsbuf *bp)
8f6c56a5
A
1256{
1257 struct nfsmount *nmp;
1258
1259 if (!ISSET(bp->nb_flags, NB_NEEDCOMMIT))
1260 return;
1261
2d21ac55
A
1262 nmp = NFSTONMP(np);
1263 if (!nmp)
1264 return;
1265 if (!ISSET(bp->nb_flags, NB_STALEWVERF) && (bp->nb_verf == nmp->nm_verf))
8f6c56a5
A
1266 return;
1267
2d21ac55
A
1268 /* write verifier changed, clear commit/wverf flags */
1269 CLR(bp->nb_flags, (NB_NEEDCOMMIT | NB_STALEWVERF));
1270 bp->nb_verf = 0;
1271 nfs_lock(np, NFS_NODE_LOCK_FORCE);
8f6c56a5
A
1272 np->n_needcommitcnt--;
1273 CHECK_NEEDCOMMITCNT(np);
2d21ac55 1274 nfs_unlock(np);
8f6c56a5
A
1275}
1276
91447636
A
1277/*
1278 * add a reference to a buffer so it doesn't disappear while being used
1279 * (must be called with nfs_buf_mutex held)
1280 */
1281void
1282nfs_buf_refget(struct nfsbuf *bp)
1283{
1284 bp->nb_refs++;
1285}
1286/*
1287 * release a reference on a buffer
1288 * (must be called with nfs_buf_mutex held)
1289 */
1290void
1291nfs_buf_refrele(struct nfsbuf *bp)
1292{
1293 bp->nb_refs--;
1294}
1295
1296/*
1297 * mark a particular buffer as BUSY
1298 * (must be called with nfs_buf_mutex held)
1299 */
1300errno_t
1301nfs_buf_acquire(struct nfsbuf *bp, int flags, int slpflag, int slptimeo)
1302{
1303 errno_t error;
1304 struct timespec ts;
1305
1306 if (ISSET(bp->nb_lflags, NBL_BUSY)) {
1307 /*
1308 * since the mutex_lock may block, the buffer
1309 * may become BUSY, so we need to recheck for
1310 * a NOWAIT request
1311 */
1312 if (flags & NBAC_NOWAIT)
1313 return (EBUSY);
1314 SET(bp->nb_lflags, NBL_WANTED);
1315
2d21ac55
A
1316 ts.tv_sec = (slptimeo/100);
1317 /* the hz value is 100; which leads to 10ms */
1318 ts.tv_nsec = (slptimeo % 100) * 10 * NSEC_PER_USEC * 1000;
91447636 1319
2d21ac55
A
1320 error = msleep(bp, nfs_buf_mutex, slpflag | (PRIBIO + 1),
1321 "nfs_buf_acquire", &ts);
1322 if (error)
1323 return (error);
1324 return (EAGAIN);
91447636
A
1325 }
1326 if (flags & NBAC_REMOVE)
1327 nfs_buf_remfree(bp);
1328 SET(bp->nb_lflags, NBL_BUSY);
1329
1330 return (0);
1331}
1332
1333/*
1334 * simply drop the BUSY status of a buffer
1335 * (must be called with nfs_buf_mutex held)
1336 */
1337void
1338nfs_buf_drop(struct nfsbuf *bp)
1339{
1340 int need_wakeup = 0;
1341
1342 if (!ISSET(bp->nb_lflags, NBL_BUSY))
1343 panic("nfs_buf_drop: buffer not busy!");
1344 if (ISSET(bp->nb_lflags, NBL_WANTED)) {
2d21ac55 1345 /* delay the actual wakeup until after we clear NBL_BUSY */
91447636
A
1346 need_wakeup = 1;
1347 }
1348 /* Unlock the buffer. */
1349 CLR(bp->nb_lflags, (NBL_BUSY | NBL_WANTED));
1350
1351 if (need_wakeup)
1352 wakeup(bp);
1353}
1354
1355/*
1356 * prepare for iterating over an nfsnode's buffer list
1357 * this lock protects the queue manipulation
1358 * (must be called with nfs_buf_mutex held)
1359 */
1360int
2d21ac55 1361nfs_buf_iterprepare(nfsnode_t np, struct nfsbuflists *iterheadp, int flags)
91447636
A
1362{
1363 struct nfsbuflists *listheadp;
1364
1365 if (flags & NBI_DIRTY)
1366 listheadp = &np->n_dirtyblkhd;
1367 else
1368 listheadp = &np->n_cleanblkhd;
1369
1370 if ((flags & NBI_NOWAIT) && (np->n_bufiterflags & NBI_ITER)) {
1371 LIST_INIT(iterheadp);
1372 return(EWOULDBLOCK);
1373 }
1374
1375 while (np->n_bufiterflags & NBI_ITER) {
1376 np->n_bufiterflags |= NBI_ITERWANT;
2d21ac55 1377 msleep(&np->n_bufiterflags, nfs_buf_mutex, 0, "nfs_buf_iterprepare", NULL);
91447636
A
1378 }
1379 if (LIST_EMPTY(listheadp)) {
1380 LIST_INIT(iterheadp);
1381 return(EINVAL);
1382 }
1383 np->n_bufiterflags |= NBI_ITER;
1384
1385 iterheadp->lh_first = listheadp->lh_first;
1386 listheadp->lh_first->nb_vnbufs.le_prev = &iterheadp->lh_first;
1387 LIST_INIT(listheadp);
1388
1389 return(0);
1390}
1391
1392/*
2d21ac55 1393 * clean up after iterating over an nfsnode's buffer list
91447636
A
1394 * this lock protects the queue manipulation
1395 * (must be called with nfs_buf_mutex held)
1396 */
1397void
2d21ac55 1398nfs_buf_itercomplete(nfsnode_t np, struct nfsbuflists *iterheadp, int flags)
91447636
A
1399{
1400 struct nfsbuflists * listheadp;
1401 struct nfsbuf *bp;
1402
1403 if (flags & NBI_DIRTY)
1404 listheadp = &np->n_dirtyblkhd;
1405 else
1406 listheadp = &np->n_cleanblkhd;
1407
1408 while (!LIST_EMPTY(iterheadp)) {
1409 bp = LIST_FIRST(iterheadp);
1410 LIST_REMOVE(bp, nb_vnbufs);
1411 LIST_INSERT_HEAD(listheadp, bp, nb_vnbufs);
1412 }
1413
1414 np->n_bufiterflags &= ~NBI_ITER;
1415 if (np->n_bufiterflags & NBI_ITERWANT) {
1416 np->n_bufiterflags &= ~NBI_ITERWANT;
1417 wakeup(&np->n_bufiterflags);
1418 }
1419}
1420
1c79356b
A
1421
1422/*
2d21ac55 1423 * Read an NFS buffer for a file.
1c79356b
A
1424 */
1425int
2d21ac55 1426nfs_buf_read(struct nfsbuf *bp)
1c79356b 1427{
2d21ac55
A
1428 int error = 0;
1429 nfsnode_t np;
1430 thread_t thd;
1431 kauth_cred_t cred;
55e303ae 1432
2d21ac55
A
1433 np = bp->nb_np;
1434 cred = bp->nb_rcred;
1435 if (IS_VALID_CRED(cred))
1436 kauth_cred_ref(cred);
1437 thd = ISSET(bp->nb_flags, NB_ASYNC) ? NULL : current_thread();
1c79356b 1438
2d21ac55
A
1439 /* sanity checks */
1440 if (!ISSET(bp->nb_flags, NB_READ))
1441 panic("nfs_buf_read: !NB_READ");
1442 if (ISSET(bp->nb_flags, NB_DONE))
1443 CLR(bp->nb_flags, NB_DONE);
91447636 1444
2d21ac55 1445 NFS_BUF_MAP(bp);
0c530ab8 1446
2d21ac55
A
1447 OSAddAtomic(1, (SInt32 *)&nfsstats.read_bios);
1448
1449 error = nfs_buf_read_rpc(bp, thd, cred);
1c79356b 1450 /*
2d21ac55
A
1451 * For async I/O, the callbacks will finish up the
1452 * read. Otherwise, the read has already been finished.
1c79356b 1453 */
2d21ac55
A
1454
1455 if (IS_VALID_CRED(cred))
1456 kauth_cred_unref(&cred);
1457 return (error);
1458}
1459
1460/*
1461 * finish the reading of a buffer
1462 */
1463void
1464nfs_buf_read_finish(struct nfsbuf *bp)
1465{
1466 nfsnode_t np = bp->nb_np;
1467 struct nfsmount *nmp;
1468
1469 if (!ISSET(bp->nb_flags, NB_ERROR)) {
1470 /* update valid range */
1471 bp->nb_validoff = 0;
1472 bp->nb_validend = bp->nb_endio;
1473 if (bp->nb_endio < bp->nb_bufsize) {
1474 /*
1475 * The read may be short because we have unflushed writes
1476 * that are extending the file size and the reads hit the
1477 * (old) EOF on the server. So, just make sure nb_validend
1478 * correctly tracks EOF.
1479 * Note that the missing data should have already been zeroed
1480 * in nfs_buf_read_rpc_finish().
1481 */
1482 off_t boff = NBOFF(bp);
1483 if ((off_t)np->n_size >= (boff + bp->nb_bufsize))
1484 bp->nb_validend = bp->nb_bufsize;
1485 else if ((off_t)np->n_size >= boff)
1486 bp->nb_validend = np->n_size - boff;
1487 else
1488 bp->nb_validend = 0;
91447636 1489 }
2d21ac55
A
1490 if ((nmp = NFSTONMP(np)) && (nmp->nm_vers == NFS_VER2) &&
1491 ((NBOFF(bp) + bp->nb_validend) > 0x100000000LL))
1492 bp->nb_validend = 0x100000000LL - NBOFF(bp);
1493 bp->nb_valid = (1 << (round_page_32(bp->nb_validend) / PAGE_SIZE)) - 1;
1494 if (bp->nb_validend & PAGE_MASK) {
1495 /* zero-fill remainder of last page */
1496 bzero(bp->nb_data + bp->nb_validend, bp->nb_bufsize - bp->nb_validend);
91447636 1497 }
2d21ac55
A
1498 }
1499 nfs_buf_iodone(bp);
1500}
1501
1502/*
1503 * initiate the NFS READ RPC(s) for a buffer
1504 */
1505int
1506nfs_buf_read_rpc(struct nfsbuf *bp, thread_t thd, kauth_cred_t cred)
1507{
1508 struct nfsmount *nmp;
1509 nfsnode_t np = bp->nb_np;
1510 int error = 0, nfsvers, async;
1511 int offset, length, nmrsize, nrpcs, len;
1512 off_t boff;
1513 struct nfsreq *req;
1514 struct nfsreq_cbinfo cb;
1515
1516 nmp = NFSTONMP(np);
1517 if (!nmp) {
1518 bp->nb_error = error = ENXIO;
1519 SET(bp->nb_flags, NB_ERROR);
1520 nfs_buf_iodone(bp);
1521 return (error);
1522 }
1523 nfsvers = nmp->nm_vers;
1524 nmrsize = nmp->nm_rsize;
1525
1526 boff = NBOFF(bp);
1527 offset = 0;
1528 length = bp->nb_bufsize;
1529
1530 if (nfsvers == NFS_VER2) {
1531 if (boff > 0xffffffffLL) {
1532 bp->nb_error = error = EFBIG;
1533 SET(bp->nb_flags, NB_ERROR);
1534 nfs_buf_iodone(bp);
91447636
A
1535 return (error);
1536 }
2d21ac55
A
1537 if ((boff + length - 1) > 0xffffffffLL)
1538 length = 0x100000000LL - boff;
91447636
A
1539 }
1540
2d21ac55
A
1541 /* Note: Can only do async I/O if nfsiods are configured. */
1542 async = (bp->nb_flags & NB_ASYNC);
1543 cb.rcb_func = async ? nfs_buf_read_rpc_finish : NULL;
1544 cb.rcb_bp = bp;
1545
1546 bp->nb_offio = bp->nb_endio = 0;
1547 bp->nb_rpcs = nrpcs = (length + nmrsize - 1) / nmrsize;
1548 if (async && (nrpcs > 1)) {
1549 SET(bp->nb_flags, NB_MULTASYNCRPC);
1550 } else {
1551 CLR(bp->nb_flags, NB_MULTASYNCRPC);
1c79356b 1552 }
1c79356b 1553
2d21ac55
A
1554 while (length > 0) {
1555 if (ISSET(bp->nb_flags, NB_ERROR)) {
1556 error = bp->nb_error;
91447636 1557 break;
2d21ac55
A
1558 }
1559 len = (length > nmrsize) ? nmrsize : length;
1560 cb.rcb_args[0] = offset;
1561 cb.rcb_args[1] = len;
1562 req = NULL;
1563 error = nmp->nm_funcs->nf_read_rpc_async(np, boff + offset, len, thd, cred, &cb, &req);
1564 if (error)
1c79356b 1565 break;
2d21ac55
A
1566 offset += len;
1567 length -= len;
1568 if (async)
1569 continue;
1570 nfs_buf_read_rpc_finish(req);
1571 if (ISSET(bp->nb_flags, NB_ERROR)) {
1572 error = bp->nb_error;
1573 break;
1574 }
1575 }
55e303ae 1576
2d21ac55 1577 if (length > 0) {
55e303ae 1578 /*
2d21ac55
A
1579 * Something bad happened while trying to send the RPC(s).
1580 * Wait for any outstanding requests to complete.
55e303ae 1581 */
2d21ac55
A
1582 bp->nb_error = error;
1583 SET(bp->nb_flags, NB_ERROR);
1584 if (ISSET(bp->nb_flags, NB_MULTASYNCRPC)) {
1585 nrpcs = (length + nmrsize - 1) / nmrsize;
1586 lck_mtx_lock(nfs_buf_mutex);
1587 bp->nb_rpcs -= nrpcs;
1588 if (bp->nb_rpcs == 0) {
1589 /* No RPCs left, so the buffer's done */
1590 lck_mtx_unlock(nfs_buf_mutex);
1591 nfs_buf_iodone(bp);
1592 } else {
1593 /* wait for the last RPC to mark it done */
1594 while (bp->nb_rpcs > 0)
1595 msleep(&bp->nb_rpcs, nfs_buf_mutex, 0,
1596 "nfs_buf_read_rpc_cancel", NULL);
1597 lck_mtx_unlock(nfs_buf_mutex);
55e303ae 1598 }
2d21ac55
A
1599 } else {
1600 nfs_buf_iodone(bp);
55e303ae 1601 }
2d21ac55 1602 }
55e303ae 1603
2d21ac55
A
1604 return (error);
1605}
1c79356b 1606
2d21ac55
A
1607/*
1608 * finish up an NFS READ RPC on a buffer
1609 */
1610void
1611nfs_buf_read_rpc_finish(struct nfsreq *req)
1612{
1613 struct nfsmount *nmp;
1614 size_t rlen;
1615 struct nfsreq_cbinfo cb;
1616 struct nfsbuf *bp;
1617 int error = 0, nfsvers, offset, length, eof = 0, multasyncrpc, finished;
1618 void *wakeme = NULL;
1619 struct nfsreq *rreq = NULL;
1620 nfsnode_t np;
1621 thread_t thd;
1622 kauth_cred_t cred;
1623 struct uio uio;
1624 struct iovec_32 io;
1625
1626finish:
1627 np = req->r_np;
1628 thd = req->r_thread;
1629 cred = req->r_cred;
1630 if (IS_VALID_CRED(cred))
1631 kauth_cred_ref(cred);
1632 cb = req->r_callback;
1633 bp = cb.rcb_bp;
1634
1635 nmp = NFSTONMP(np);
1636 if (!nmp) {
1637 SET(bp->nb_flags, NB_ERROR);
1638 bp->nb_error = error = ENXIO;
1639 }
1640 if (error || ISSET(bp->nb_flags, NB_ERROR)) {
1641 /* just drop it */
1642 nfs_request_async_cancel(req);
1643 goto out;
1644 }
1645
1646 nfsvers = nmp->nm_vers;
1647 offset = cb.rcb_args[0];
1648 rlen = length = cb.rcb_args[1];
1649
1650 uio.uio_iovs.iov32p = &io;
1651 uio.uio_iovcnt = 1;
1652 uio.uio_rw = UIO_READ;
1653#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
1654 uio.uio_segflg = UIO_SYSSPACE;
1655#else
1656 uio.uio_segflg = UIO_SYSSPACE32;
1657#endif
1658 io.iov_len = length;
1659 uio_uio_resid_set(&uio, io.iov_len);
1660 uio.uio_offset = NBOFF(bp) + offset;
1661 io.iov_base = (uintptr_t) bp->nb_data + offset;
1662
1663 /* finish the RPC */
1664 error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req, &uio, &rlen, &eof);
1665 if ((error == EINPROGRESS) && cb.rcb_func) {
1666 /* async request restarted */
1667 if (IS_VALID_CRED(cred))
1668 kauth_cred_unref(&cred);
1669 return;
1670 }
1671
1672 if (error) {
1673 SET(bp->nb_flags, NB_ERROR);
1674 bp->nb_error = error;
1675 goto out;
1676 }
1677
1678 if ((rlen > 0) && (bp->nb_endio < (offset + (int)rlen)))
1679 bp->nb_endio = offset + rlen;
1680
1681 if ((nfsvers == NFS_VER2) || eof || (rlen == 0)) {
1682 /* zero out the remaining data (up to EOF) */
1683 off_t rpcrem, eofrem, rem;
1684 rpcrem = (length - rlen);
1685 eofrem = np->n_size - (NBOFF(bp) + offset + rlen);
1686 rem = (rpcrem < eofrem) ? rpcrem : eofrem;
1687 if (rem > 0)
1688 bzero(bp->nb_data + offset + rlen, rem);
1689 } else if (((int)rlen < length) && !ISSET(bp->nb_flags, NB_ERROR)) {
1690 /*
1691 * short read
1692 *
1693 * We haven't hit EOF and we didn't get all the data
1694 * requested, so we need to issue another read for the rest.
1695 * (Don't bother if the buffer already hit an error.)
1696 */
1697 offset += rlen;
1698 length -= rlen;
1699 cb.rcb_args[0] = offset;
1700 cb.rcb_args[1] = length;
1701 error = nmp->nm_funcs->nf_read_rpc_async(np, offset, length, thd, cred, &cb, &rreq);
1702 if (!error) {
1703 if (IS_VALID_CRED(cred))
1704 kauth_cred_unref(&cred);
1705 if (!cb.rcb_func) {
1706 /* if !async we'll need to wait for this RPC to finish */
1707 req = rreq;
1708 goto finish;
1709 }
1710 /*
1711 * We're done here.
1712 * Outstanding RPC count is unchanged.
1713 * Callback will be called when RPC is done.
1714 */
1715 return;
1716 }
1717 SET(bp->nb_flags, NB_ERROR);
1718 bp->nb_error = error;
1719 }
1720
1721out:
1722 if (IS_VALID_CRED(cred))
1723 kauth_cred_unref(&cred);
1724
1725 /*
1726 * Decrement outstanding RPC count on buffer
1727 * and call nfs_buf_read_finish on last RPC.
1728 *
1729 * (Note: when there are multiple async RPCs issued for a
1730 * buffer we need nfs_buffer_mutex to avoid problems when
1731 * aborting a partially-initiated set of RPCs)
1732 */
1733
1734 multasyncrpc = ISSET(bp->nb_flags, NB_MULTASYNCRPC);
1735 if (multasyncrpc)
1736 lck_mtx_lock(nfs_buf_mutex);
1737
1738 bp->nb_rpcs--;
1739 finished = (bp->nb_rpcs == 0);
1740
1741 if (multasyncrpc)
1742 lck_mtx_unlock(nfs_buf_mutex);
1743
1744 if (finished) {
1745 if (multasyncrpc)
1746 wakeme = &bp->nb_rpcs;
1747 nfs_buf_read_finish(bp);
1748 if (wakeme)
1749 wakeup(wakeme);
1750 }
1751}
1752
1753/*
1754 * Do buffer readahead.
1755 * Initiate async I/O to read buffers not in cache.
1756 */
1757static int
1758nfs_buf_readahead(nfsnode_t np, int ioflag, daddr64_t *rabnp, daddr64_t lastrabn, thread_t thd, kauth_cred_t cred)
1759{
1760 struct nfsmount *nmp = NFSTONMP(np);
1761 struct nfsbuf *bp;
1762 int error = 0, nra;
1763
1764 if (!nmp)
1765 return (ENXIO);
1766 if (nmp->nm_readahead <= 0)
1767 return (0);
1768 if (*rabnp > lastrabn)
1769 return (0);
1770
1771 for (nra = 0; (nra < nmp->nm_readahead) && (*rabnp <= lastrabn); nra++, *rabnp = *rabnp + 1) {
1772 /* check if block exists and is valid. */
1773 error = nfs_buf_get(np, *rabnp, nmp->nm_biosize, thd, NBLK_READ|NBLK_NOWAIT, &bp);
1774 if (error)
1775 break;
1776 if (!bp)
1777 continue;
1778 if ((ioflag & IO_NOCACHE) && ISSET(bp->nb_flags, NB_CACHE) &&
1779 !bp->nb_dirty && !ISSET(bp->nb_flags, (NB_DELWRI|NB_NCRDAHEAD))) {
1780 CLR(bp->nb_flags, NB_CACHE);
1781 bp->nb_valid = 0;
1782 bp->nb_validoff = bp->nb_validend = -1;
1783 }
1784 if ((bp->nb_dirtyend <= 0) && !bp->nb_dirty &&
1785 !ISSET(bp->nb_flags, (NB_CACHE|NB_DELWRI))) {
1786 SET(bp->nb_flags, (NB_READ|NB_ASYNC));
1787 if (ioflag & IO_NOCACHE)
1788 SET(bp->nb_flags, NB_NCRDAHEAD);
1789 if (!IS_VALID_CRED(bp->nb_rcred) && IS_VALID_CRED(cred)) {
1790 kauth_cred_ref(cred);
1791 bp->nb_rcred = cred;
1792 }
1793 if ((error = nfs_buf_read(bp)))
1794 break;
1795 continue;
1796 }
1797 nfs_buf_release(bp, 1);
1798 }
1799 return (error);
1800}
1801
1802/*
1803 * NFS buffer I/O for reading files/directories.
1804 */
1805int
1806nfs_bioread(nfsnode_t np, struct uio *uio, int ioflag, int *eofflag, vfs_context_t ctx)
1807{
1808 vnode_t vp = NFSTOV(np);
1809 struct nfsbuf *bp = NULL;
1810 struct nfs_vattr nvattr;
1811 struct nfsmount *nmp = VTONMP(vp);
1812 daddr64_t lbn, rabn = 0, lastrabn, maxrabn = -1, tlbn;
1813 off_t diff;
1814 int error = 0, n = 0, on = 0;
1815 int nfsvers, biosize;
1816 caddr_t dp;
1817 struct dirent *direntp = NULL;
1818 enum vtype vtype;
1819 thread_t thd;
1820 kauth_cred_t cred;
1821
1822 FSDBG_TOP(514, np, uio->uio_offset, uio_uio_resid(uio), ioflag);
1823
1824 if (uio_uio_resid(uio) == 0) {
1825 FSDBG_BOT(514, np, 0xd1e0001, 0, 0);
1826 return (0);
1827 }
1828 if (uio->uio_offset < 0) {
1829 FSDBG_BOT(514, np, 0xd1e0002, 0, EINVAL);
1830 return (EINVAL);
1831 }
1832
1833 nfsvers = nmp->nm_vers;
1834 biosize = nmp->nm_biosize;
1835 thd = vfs_context_thread(ctx);
1836 cred = vfs_context_ucred(ctx);
1837
1838 vtype = vnode_vtype(vp);
1839 if ((vtype != VREG) && (vtype != VDIR)) {
1840 printf("nfs_bioread: type %x unexpected\n", vtype);
1841 FSDBG_BOT(514, np, 0xd1e0016, 0, EINVAL);
1842 return (EINVAL);
1843 }
1844
1845 /*
1846 * For nfs, cache consistency can only be maintained approximately.
1847 * Although RFC1094 does not specify the criteria, the following is
1848 * believed to be compatible with the reference port.
1849 * For nfs:
1850 * If the file's modify time on the server has changed since the
1851 * last read rpc or you have written to the file,
1852 * you may have lost data cache consistency with the
1853 * server, so flush all of the file's data out of the cache.
1854 * Then force a getattr rpc to ensure that you have up to date
1855 * attributes.
1856 * NB: This implies that cache data can be read when up to
1857 * NFS_MAXATTRTIMEO seconds out of date. If you find that you need
1858 * current attributes this could be forced by calling
1859 * NATTRINVALIDATE() before the nfs_getattr() call.
1860 */
1861
1862 if (ISSET(np->n_flag, NUPDATESIZE))
1863 nfs_data_update_size(np, 0);
1864
1865 if ((error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) {
1866 FSDBG_BOT(514, np, 0xd1e0222, 0, error);
1867 return (error);
1868 }
1869
1870 if (np->n_flag & NNEEDINVALIDATE) {
1871 np->n_flag &= ~NNEEDINVALIDATE;
1872 nfs_unlock(np);
1873 nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1);
1874 if ((error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) {
1875 FSDBG_BOT(514, np, 0xd1e0322, 0, error);
1876 return (error);
1877 }
1878 }
1879
1880 if (np->n_flag & NMODIFIED) {
1881 if (vtype == VDIR) {
1882 nfs_invaldir(np);
1883 nfs_unlock(np);
1884 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
1885 if (!error)
1886 error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
1887 if (error) {
1888 FSDBG_BOT(514, np, 0xd1e0003, 0, error);
1889 return (error);
1890 }
1891 }
1892 NATTRINVALIDATE(np);
1893 error = nfs_getattr(np, &nvattr, ctx, 1);
1894 if (error) {
1895 nfs_unlock(np);
1896 FSDBG_BOT(514, np, 0xd1e0004, 0, error);
1897 return (error);
1898 }
1899 if (vtype == VDIR) {
1900 /* if directory changed, purge any name cache entries */
1901 if (NFS_CHANGED_NC(nfsvers, np, &nvattr))
1902 cache_purge(vp);
1903 NFS_CHANGED_UPDATE_NC(nfsvers, np, &nvattr);
1904 }
1905 NFS_CHANGED_UPDATE(nfsvers, np, &nvattr);
1906 } else {
1907 error = nfs_getattr(np, &nvattr, ctx, 1);
1908 if (error) {
1909 nfs_unlock(np);
1910 FSDBG_BOT(514, np, 0xd1e0005, 0, error);
1911 return (error);
1912 }
1913 if (NFS_CHANGED(nfsvers, np, &nvattr)) {
1914 if (vtype == VDIR) {
1915 nfs_invaldir(np);
1916 /* purge name cache entries */
1917 if (NFS_CHANGED_NC(nfsvers, np, &nvattr))
1918 cache_purge(vp);
1919 }
1920 nfs_unlock(np);
1921 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
1922 if (!error)
1923 error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
1924 if (error) {
1925 FSDBG_BOT(514, np, 0xd1e0006, 0, error);
1926 return (error);
1927 }
1928 if (vtype == VDIR)
1929 NFS_CHANGED_UPDATE_NC(nfsvers, np, &nvattr);
1930 NFS_CHANGED_UPDATE(nfsvers, np, &nvattr);
1931 }
1932 }
1933
1934 nfs_unlock(np);
1935
1936 if (vtype == VREG) {
1937 if ((ioflag & IO_NOCACHE) && (uio_uio_resid(uio) < (2*biosize))) {
1938 /* We have only a block or so to read, just do the rpc directly. */
1939 error = nfs_read_rpc(np, uio, ctx);
1940 FSDBG_BOT(514, np, uio->uio_offset, uio_uio_resid(uio), error);
1941 return (error);
1942 }
1943 /*
1944 * set up readahead - which may be limited by:
1945 * + current request length (for IO_NOCACHE)
1946 * + readahead setting
1947 * + file size
1948 */
1949 if (nmp->nm_readahead > 0) {
1950 off_t end = uio->uio_offset + uio_uio_resid(uio);
1951 if (end > (off_t)np->n_size)
1952 end = np->n_size;
1953 rabn = uio->uio_offset / biosize;
1954 maxrabn = (end - 1) / biosize;
1955 if (!(ioflag & IO_NOCACHE) &&
1956 (!rabn || (rabn == np->n_lastread) || (rabn == (np->n_lastread+1)))) {
1957 maxrabn += nmp->nm_readahead;
1958 if ((maxrabn * biosize) >= (off_t)np->n_size)
1959 maxrabn = ((off_t)np->n_size - 1)/biosize;
1960 }
1961 } else {
1962 rabn = maxrabn = 0;
1963 }
1964 }
1965
1966 do {
1967
1968 if (vtype == VREG) {
1969 nfs_data_lock(np, NFS_NODE_LOCK_SHARED);
1970 lbn = uio->uio_offset / biosize;
1971
1972 /*
1973 * Copy directly from any cached pages without grabbing the bufs.
1974 *
1975 * Note: for "nocache" reads, we don't copy directly from UBC
1976 * because any cached pages will be for readahead buffers that
1977 * need to be invalidated anyway before we finish this request.
1978 */
1979 if (!(ioflag & IO_NOCACHE) &&
1980 (uio->uio_segflg == UIO_USERSPACE32 ||
1981 uio->uio_segflg == UIO_USERSPACE64 ||
1982 uio->uio_segflg == UIO_USERSPACE)) {
1983 // LP64todo - fix this!
1984 int io_resid = uio_uio_resid(uio);
1985 diff = np->n_size - uio->uio_offset;
1986 if (diff < io_resid)
1987 io_resid = diff;
1988 if (io_resid > 0) {
1989 error = cluster_copy_ubc_data(vp, uio, &io_resid, 0);
91447636 1990 if (error) {
2d21ac55
A
1991 nfs_data_unlock(np);
1992 FSDBG_BOT(514, np, uio->uio_offset, 0xcacefeed, error);
91447636
A
1993 return (error);
1994 }
2d21ac55
A
1995 }
1996 /* count any biocache reads that we just copied directly */
1997 if (lbn != (uio->uio_offset / biosize)) {
1998 OSAddAtomic((uio->uio_offset / biosize) - lbn, (SInt32*)&nfsstats.biocache_reads);
1999 FSDBG(514, np, 0xcacefeed, uio->uio_offset, error);
2000 }
2001 }
2002
2003 lbn = uio->uio_offset / biosize;
2004 on = uio->uio_offset % biosize;
2005 np->n_lastread = (uio->uio_offset - 1) / biosize;
2006
2007 /* adjust readahead block number, if necessary */
2008 if (rabn < lbn)
2009 rabn = lbn;
2010 lastrabn = MIN(maxrabn, lbn + nmp->nm_readahead);
2011 if (rabn <= lastrabn) { /* start readaheads */
2012 error = nfs_buf_readahead(np, ioflag, &rabn, lastrabn, thd, cred);
2013 if (error) {
2014 nfs_data_unlock(np);
2015 FSDBG_BOT(514, np, 0xd1e000b, 1, error);
2016 return (error);
55e303ae 2017 }
1c79356b
A
2018 }
2019
91447636 2020 if ((uio_uio_resid(uio) <= 0) || (uio->uio_offset >= (off_t)np->n_size)) {
2d21ac55
A
2021 nfs_data_unlock(np);
2022 FSDBG_BOT(514, np, uio->uio_offset, uio_uio_resid(uio), 0xaaaaaaaa);
55e303ae
A
2023 return (0);
2024 }
2025
91447636 2026 OSAddAtomic(1, (SInt32*)&nfsstats.biocache_reads);
55e303ae 2027
1c79356b
A
2028 /*
2029 * If the block is in the cache and has the required data
2030 * in a valid region, just copy it out.
2031 * Otherwise, get the block and write back/read in,
2032 * as required.
2033 */
2034again:
91447636 2035 // LP64todo - fix this!
2d21ac55 2036 n = min((unsigned)(biosize - on), uio_uio_resid(uio));
1c79356b
A
2037 diff = np->n_size - uio->uio_offset;
2038 if (diff < n)
2039 n = diff;
55e303ae 2040
2d21ac55 2041 error = nfs_buf_get(np, lbn, biosize, thd, NBLK_READ, &bp);
91447636 2042 if (error) {
2d21ac55
A
2043 nfs_data_unlock(np);
2044 FSDBG_BOT(514, np, 0xd1e000c, 0, error);
2045 return (error);
2046 }
2047
2048 if ((ioflag & IO_NOCACHE) && ISSET(bp->nb_flags, NB_CACHE)) {
2049 /*
2050 * IO_NOCACHE found a cached buffer.
2051 * Flush the buffer if it's dirty.
2052 * Invalidate the data if it wasn't just read
2053 * in as part of a "nocache readahead".
2054 */
2055 if (bp->nb_dirty || (bp->nb_dirtyend > 0)) {
2056 /* so write the buffer out and try again */
2057 SET(bp->nb_flags, NB_NOCACHE);
2058 goto flushbuffer;
2059 }
2060 if (!ISSET(bp->nb_flags, NB_NCRDAHEAD)) {
2061 CLR(bp->nb_flags, NB_CACHE);
2062 bp->nb_valid = 0;
2063 } else {
2064 CLR(bp->nb_flags, NB_NCRDAHEAD);
2065 }
55e303ae
A
2066 }
2067
2068 /* if any pages are valid... */
2069 if (bp->nb_valid) {
2070 /* ...check for any invalid pages in the read range */
2071 int pg, firstpg, lastpg, dirtypg;
2072 dirtypg = firstpg = lastpg = -1;
2073 pg = on/PAGE_SIZE;
2074 while (pg <= (on + n - 1)/PAGE_SIZE) {
2075 if (!NBPGVALID(bp,pg)) {
2076 if (firstpg < 0)
2077 firstpg = pg;
2078 lastpg = pg;
2079 } else if (firstpg >= 0 && dirtypg < 0 && NBPGDIRTY(bp,pg))
2080 dirtypg = pg;
2081 pg++;
2082 }
2083
2084 /* if there are no invalid pages, we're all set */
2085 if (firstpg < 0) {
2086 if (bp->nb_validoff < 0) {
2087 /* valid range isn't set up, so */
2088 /* set it to what we know is valid */
91447636
A
2089 bp->nb_validoff = trunc_page(on);
2090 bp->nb_validend = round_page(on+n);
55e303ae
A
2091 nfs_buf_normalize_valid_range(np, bp);
2092 }
2093 goto buffer_ready;
2094 }
2095
2096 /* there are invalid pages in the read range */
2d21ac55
A
2097 if (((dirtypg > firstpg) && (dirtypg < lastpg)) ||
2098 (((firstpg*PAGE_SIZE) < bp->nb_dirtyend) && (((lastpg+1)*PAGE_SIZE) > bp->nb_dirtyoff))) {
2099 /* there are also dirty page(s) (or range) in the read range, */
55e303ae 2100 /* so write the buffer out and try again */
2d21ac55 2101flushbuffer:
55e303ae
A
2102 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL));
2103 SET(bp->nb_flags, NB_ASYNC);
2d21ac55 2104 if (!IS_VALID_CRED(bp->nb_wcred)) {
91447636
A
2105 kauth_cred_ref(cred);
2106 bp->nb_wcred = cred;
2107 }
55e303ae
A
2108 error = nfs_buf_write(bp);
2109 if (error) {
2d21ac55
A
2110 nfs_data_unlock(np);
2111 FSDBG_BOT(514, np, 0xd1e000d, 0, error);
55e303ae
A
2112 return (error);
2113 }
1c79356b
A
2114 goto again;
2115 }
55e303ae 2116 if (!bp->nb_dirty && bp->nb_dirtyend <= 0 &&
2d21ac55 2117 (lastpg - firstpg + 1) > (biosize/PAGE_SIZE)/2) {
55e303ae
A
2118 /* we need to read in more than half the buffer and the */
2119 /* buffer's not dirty, so just fetch the whole buffer */
2120 bp->nb_valid = 0;
2121 } else {
2122 /* read the page range in */
91447636
A
2123 uio_t auio;
2124 char uio_buf[ UIO_SIZEOF(1) ];
2125
55e303ae 2126 NFS_BUF_MAP(bp);
2d21ac55 2127 auio = uio_createwithbuffer(1, (NBOFF(bp) + firstpg * PAGE_SIZE_64),
91447636
A
2128 UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
2129 if (!auio) {
2130 error = ENOMEM;
2131 } else {
2d21ac55 2132 uio_addiov(auio, CAST_USER_ADDR_T((bp->nb_data + firstpg * PAGE_SIZE)),
91447636 2133 ((lastpg - firstpg + 1) * PAGE_SIZE));
2d21ac55 2134 error = nfs_read_rpc(np, auio, ctx);
91447636 2135 }
55e303ae 2136 if (error) {
2d21ac55 2137 if (ioflag & IO_NOCACHE)
91447636 2138 SET(bp->nb_flags, NB_NOCACHE);
483a1d10 2139 nfs_buf_release(bp, 1);
2d21ac55
A
2140 nfs_data_unlock(np);
2141 FSDBG_BOT(514, np, 0xd1e000e, 0, error);
55e303ae
A
2142 return (error);
2143 }
2144 /* Make sure that the valid range is set to cover this read. */
2145 bp->nb_validoff = trunc_page_32(on);
2146 bp->nb_validend = round_page_32(on+n);
2147 nfs_buf_normalize_valid_range(np, bp);
91447636 2148 if (uio_resid(auio) > 0) {
55e303ae
A
2149 /* if short read, must have hit EOF, */
2150 /* so zero the rest of the range */
91447636 2151 bzero(CAST_DOWN(caddr_t, uio_curriovbase(auio)), uio_resid(auio));
55e303ae
A
2152 }
2153 /* mark the pages (successfully read) as valid */
2154 for (pg=firstpg; pg <= lastpg; pg++)
2155 NBPGVALID_SET(bp,pg);
2156 }
1c79356b 2157 }
55e303ae
A
2158 /* if no pages are valid, read the whole block */
2159 if (!bp->nb_valid) {
2d21ac55
A
2160 if (!IS_VALID_CRED(bp->nb_rcred) && IS_VALID_CRED(cred)) {
2161 kauth_cred_ref(cred);
2162 bp->nb_rcred = cred;
2163 }
55e303ae
A
2164 SET(bp->nb_flags, NB_READ);
2165 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL));
2d21ac55 2166 error = nfs_buf_read(bp);
55e303ae 2167 if (error) {
2d21ac55 2168 nfs_data_unlock(np);
483a1d10 2169 nfs_buf_release(bp, 1);
2d21ac55 2170 FSDBG_BOT(514, np, 0xd1e000f, 0, error);
55e303ae
A
2171 return (error);
2172 }
2173 }
2174buffer_ready:
55e303ae
A
2175 /* validate read range against valid range and clip */
2176 if (bp->nb_validend > 0) {
2177 diff = (on >= bp->nb_validend) ? 0 : (bp->nb_validend - on);
2178 if (diff < n)
2179 n = diff;
2180 }
2181 if (n > 0)
2182 NFS_BUF_MAP(bp);
2d21ac55 2183 } else if (vtype == VDIR) {
91447636 2184 OSAddAtomic(1, (SInt32*)&nfsstats.biocache_readdirs);
2d21ac55
A
2185 error = nfs_lock(np, NFS_NODE_LOCK_SHARED);
2186 if (error || (np->n_direofoffset && (uio->uio_offset >= np->n_direofoffset))) {
2187 if (!error)
2188 nfs_unlock(np);
2189 if (eofflag)
2190 *eofflag = 1;
2191 FSDBG_BOT(514, np, 0xde0f0001, 0, 0);
55e303ae 2192 return (0);
1c79356b 2193 }
2d21ac55 2194 nfs_unlock(np);
1c79356b
A
2195 lbn = uio->uio_offset / NFS_DIRBLKSIZ;
2196 on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
2d21ac55 2197 error = nfs_buf_get(np, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ, &bp);
91447636 2198 if (error) {
2d21ac55 2199 FSDBG_BOT(514, np, 0xd1e0012, 0, error);
91447636 2200 return (error);
55e303ae
A
2201 }
2202 if (!ISSET(bp->nb_flags, NB_CACHE)) {
2203 SET(bp->nb_flags, NB_READ);
2d21ac55
A
2204 error = nfs_buf_readdir(bp, ctx);
2205 if (error)
483a1d10 2206 nfs_buf_release(bp, 1);
fa4905b1 2207 while (error == NFSERR_BAD_COOKIE) {
2d21ac55
A
2208 error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
2209 if (!error) {
2210 nfs_invaldir(np);
2211 nfs_unlock(np);
2212 }
2213 error = nfs_vinvalbuf(vp, 0, ctx, 1);
fa4905b1
A
2214 /*
2215 * Yuck! The directory has been modified on the
2216 * server. The only way to get the block is by
2217 * reading from the beginning to get all the
2218 * offset cookies.
2219 */
91447636 2220 for (tlbn = 0; tlbn <= lbn && !error; tlbn++) {
2d21ac55
A
2221 if ((error = nfs_lock(np, NFS_NODE_LOCK_SHARED)))
2222 break;
fa4905b1 2223 if (np->n_direofoffset
91447636 2224 && (tlbn * NFS_DIRBLKSIZ) >= np->n_direofoffset) {
2d21ac55
A
2225 nfs_unlock(np);
2226 if (eofflag)
2227 *eofflag = 1;
2228 FSDBG_BOT(514, np, 0xde0f0002, 0, 0);
fa4905b1 2229 return (0);
55e303ae 2230 }
2d21ac55
A
2231 nfs_unlock(np);
2232 error = nfs_buf_get(np, tlbn, NFS_DIRBLKSIZ, thd, NBLK_READ, &bp);
91447636 2233 if (error) {
2d21ac55 2234 FSDBG_BOT(514, np, 0xd1e0013, 0, error);
91447636 2235 return (error);
55e303ae
A
2236 }
2237 if (!ISSET(bp->nb_flags, NB_CACHE)) {
2238 SET(bp->nb_flags, NB_READ);
2d21ac55 2239 error = nfs_buf_readdir(bp, ctx);
fa4905b1 2240 /*
55e303ae 2241 * no error + NB_INVAL == directory EOF,
fa4905b1
A
2242 * use the block.
2243 */
2d21ac55
A
2244 if (error == 0 && ISSET(bp->nb_flags, NB_INVAL)) {
2245 if (eofflag)
2246 *eofflag = 1;
fa4905b1 2247 break;
2d21ac55 2248 }
fa4905b1
A
2249 }
2250 /*
2251 * An error will throw away the block and the
2252 * for loop will break out. If no error and this
2253 * is not the block we want, we throw away the
2254 * block and go for the next one via the for loop.
2255 */
2d21ac55 2256 if (error || (tlbn < lbn))
483a1d10 2257 nfs_buf_release(bp, 1);
fa4905b1
A
2258 }
2259 }
2260 /*
2261 * The above while is repeated if we hit another cookie
2262 * error. If we hit an error and it wasn't a cookie error,
2263 * we give up.
2264 */
55e303ae 2265 if (error) {
2d21ac55 2266 FSDBG_BOT(514, np, 0xd1e0014, 0, error);
fa4905b1 2267 return (error);
55e303ae 2268 }
1c79356b 2269 }
1c79356b
A
2270 /*
2271 * Make sure we use a signed variant of min() since
2272 * the second term may be negative.
2273 */
91447636
A
2274 // LP64todo - fix this!
2275 n = lmin(uio_uio_resid(uio), bp->nb_validend - on);
fa4905b1 2276 /*
55e303ae
A
2277 * We keep track of the directory eof in
2278 * np->n_direofoffset and chop it off as an
2279 * extra step right here.
fa4905b1 2280 */
2d21ac55
A
2281 if ((error = nfs_lock(np, NFS_NODE_LOCK_SHARED))) {
2282 FSDBG_BOT(514, np, 0xd1e0115, 0, error);
2283 return (error);
2284 }
fa4905b1
A
2285 if (np->n_direofoffset &&
2286 n > np->n_direofoffset - uio->uio_offset)
2287 n = np->n_direofoffset - uio->uio_offset;
2d21ac55 2288 nfs_unlock(np);
55e303ae
A
2289 /*
2290 * Make sure that we return an integral number of entries so
2291 * that any subsequent calls will start copying from the start
2292 * of the next entry.
2293 *
2294 * If the current value of n has the last entry cut short,
2295 * set n to copy everything up to the last entry instead.
2296 */
2297 if (n > 0) {
2298 dp = bp->nb_data + on;
2299 while (dp < (bp->nb_data + on + n)) {
2300 direntp = (struct dirent *)dp;
2301 dp += direntp->d_reclen;
2302 }
2303 if (dp > (bp->nb_data + on + n))
2304 n = (dp - direntp->d_reclen) - (bp->nb_data + on);
2305 }
2d21ac55 2306 }
1c79356b 2307
2d21ac55 2308 if (n > 0)
55e303ae 2309 error = uiomove(bp->nb_data + on, (int)n, uio);
2d21ac55
A
2310
2311 if (vtype == VREG) {
2312 if (ioflag & IO_NOCACHE)
91447636 2313 SET(bp->nb_flags, NB_NOCACHE);
2d21ac55
A
2314 nfs_buf_release(bp, 1);
2315 nfs_data_unlock(np);
2316 np->n_lastread = (uio->uio_offset - 1) / biosize;
2317 } else {
2318 nfs_buf_release(bp, 1);
1c79356b 2319 }
91447636 2320 } while (error == 0 && uio_uio_resid(uio) > 0 && n > 0);
2d21ac55 2321 FSDBG_BOT(514, np, uio->uio_offset, uio_uio_resid(uio), error);
1c79356b
A
2322 return (error);
2323}
2324
2d21ac55
A
2325/*
2326 * limit the number of outstanding async I/O writes
2327 */
2328static int
2329nfs_async_write_start(struct nfsmount *nmp)
2330{
2331 int error = 0, slpflag = (nmp->nm_flag & NFSMNT_INT) ? PCATCH : 0;
2332 struct timespec ts = {1, 0};
2333
2334 if (nfs_max_async_writes <= 0)
2335 return (0);
2336 lck_mtx_lock(&nmp->nm_lock);
2337 while (!error && (nfs_max_async_writes > 0) && (nmp->nm_asyncwrites >= nfs_max_async_writes)) {
2338 if ((error = nfs_sigintr(nmp, NULL, current_thread(), 1)))
2339 break;
2340 error = msleep(&nmp->nm_asyncwrites, &nmp->nm_lock, slpflag|(PZERO-1), "nfsasyncwrites", &ts);
2341 if (error == EWOULDBLOCK)
2342 error = 0;
2343 }
2344 if (!error)
2345 nmp->nm_asyncwrites++;
2346 lck_mtx_unlock(&nmp->nm_lock);
2347 return (error);
2348}
2349static void
2350nfs_async_write_done(struct nfsmount *nmp)
2351{
2352 if (nmp->nm_asyncwrites <= 0)
2353 return;
2354 lck_mtx_lock(&nmp->nm_lock);
2355 if (nmp->nm_asyncwrites-- >= nfs_max_async_writes)
2356 wakeup(&nmp->nm_asyncwrites);
2357 lck_mtx_unlock(&nmp->nm_lock);
2358}
fa4905b1 2359
1c79356b 2360/*
2d21ac55
A
2361 * write (or commit) the given NFS buffer
2362 *
2363 * Commit the buffer if we can.
2364 * Write out any dirty range.
2365 * If any dirty pages remain, write them out.
2366 * Mark buffer done.
2367 *
2368 * For async requests, all the work beyond sending the initial
2369 * write RPC is handled in the RPC callback(s).
1c79356b
A
2370 */
2371int
2d21ac55 2372nfs_buf_write(struct nfsbuf *bp)
1c79356b 2373{
2d21ac55
A
2374 int error = 0, oldflags, async;
2375 nfsnode_t np;
2376 thread_t thd;
91447636 2377 kauth_cred_t cred;
2d21ac55
A
2378 proc_t p = current_proc();
2379 int iomode, doff, dend, firstpg, lastpg;
2380 uint32_t pagemask;
91447636 2381
2d21ac55 2382 FSDBG_TOP(553, bp, NBOFF(bp), bp->nb_flags, 0);
91447636 2383
2d21ac55
A
2384 if (!ISSET(bp->nb_lflags, NBL_BUSY))
2385 panic("nfs_buf_write: buffer is not busy???");
91447636 2386
2d21ac55
A
2387 np = bp->nb_np;
2388 async = ISSET(bp->nb_flags, NB_ASYNC);
2389 oldflags = bp->nb_flags;
91447636 2390
2d21ac55
A
2391 CLR(bp->nb_flags, (NB_READ|NB_DONE|NB_ERROR|NB_DELWRI));
2392 if (ISSET(oldflags, NB_DELWRI)) {
2393 lck_mtx_lock(nfs_buf_mutex);
2394 nfs_nbdwrite--;
2395 NFSBUFCNTCHK();
2396 lck_mtx_unlock(nfs_buf_mutex);
2397 wakeup(&nfs_nbdwrite);
91447636 2398 }
2d21ac55
A
2399
2400 /* move to clean list */
2401 if (ISSET(oldflags, (NB_ASYNC|NB_DELWRI))) {
2402 lck_mtx_lock(nfs_buf_mutex);
2403 if (bp->nb_vnbufs.le_next != NFSNOLIST)
2404 LIST_REMOVE(bp, nb_vnbufs);
2405 LIST_INSERT_HEAD(&np->n_cleanblkhd, bp, nb_vnbufs);
2406 lck_mtx_unlock(nfs_buf_mutex);
1c79356b 2407 }
2d21ac55 2408 vnode_startwrite(NFSTOV(np));
0c530ab8 2409
2d21ac55
A
2410 if (p && p->p_stats)
2411 OSIncrementAtomic(&p->p_stats->p_ru.ru_oublock);
0c530ab8 2412
2d21ac55
A
2413 cred = bp->nb_wcred;
2414 if (!IS_VALID_CRED(cred) && ISSET(bp->nb_flags, NB_READ))
2415 cred = bp->nb_rcred; /* shouldn't really happen, but... */
2416 if (IS_VALID_CRED(cred))
2417 kauth_cred_ref(cred);
2418 thd = async ? NULL : current_thread();
2419
2420 /* We need to make sure the pages are locked before doing I/O. */
2421 if (!ISSET(bp->nb_flags, NB_META) && UBCINFOEXISTS(NFSTOV(np))) {
2422 if (!ISSET(bp->nb_flags, NB_PAGELIST)) {
2423 error = nfs_buf_upl_setup(bp);
55e303ae 2424 if (error) {
2d21ac55
A
2425 printf("nfs_buf_write: upl create failed %d\n", error);
2426 SET(bp->nb_flags, NB_ERROR);
2427 bp->nb_error = error = EIO;
2428 nfs_buf_iodone(bp);
2429 goto out;
55e303ae 2430 }
2d21ac55 2431 nfs_buf_upl_check(bp);
1c79356b
A
2432 }
2433 }
55e303ae 2434
2d21ac55
A
2435 /* If NB_NEEDCOMMIT is set, a commit RPC may do the trick. */
2436 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT))
2437 nfs_buf_check_write_verifier(np, bp);
2438 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
2439 struct nfsmount *nmp = NFSTONMP(np);
2440 if (!nmp) {
2441 SET(bp->nb_flags, NB_ERROR);
2442 bp->nb_error = error = EIO;
2443 nfs_buf_iodone(bp);
2444 goto out;
2445 }
2446 SET(bp->nb_flags, NB_WRITEINPROG);
2447 error = nmp->nm_funcs->nf_commit_rpc(np, NBOFF(bp) + bp->nb_dirtyoff,
2448 bp->nb_dirtyend - bp->nb_dirtyoff, bp->nb_wcred);
2449 CLR(bp->nb_flags, NB_WRITEINPROG);
2450 if (error) {
2451 if (error != NFSERR_STALEWRITEVERF) {
2452 SET(bp->nb_flags, NB_ERROR);
2453 bp->nb_error = error;
55e303ae 2454 }
2d21ac55
A
2455 nfs_buf_iodone(bp);
2456 goto out;
2457 }
2458 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
2459 CLR(bp->nb_flags, NB_NEEDCOMMIT);
2460 nfs_lock(np, NFS_NODE_LOCK_FORCE);
2461 np->n_needcommitcnt--;
2462 CHECK_NEEDCOMMITCNT(np);
2463 nfs_unlock(np);
2464 }
2465 if (!error && (bp->nb_dirtyend > 0)) {
2466 /* sanity check the dirty range */
2467 if (NBOFF(bp) + bp->nb_dirtyend > (off_t) np->n_size) {
2468 bp->nb_dirtyend = np->n_size - NBOFF(bp);
2469 if (bp->nb_dirtyoff >= bp->nb_dirtyend)
2470 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
55e303ae 2471 }
91447636 2472 }
2d21ac55
A
2473 if (!error && (bp->nb_dirtyend > 0)) {
2474 /* there's a dirty range that needs to be written out */
2475 NFS_BUF_MAP(bp);
2476
2477 doff = bp->nb_dirtyoff;
2478 dend = bp->nb_dirtyend;
2479
2480 /* if doff page is dirty, move doff to start of page */
2481 if (NBPGDIRTY(bp, doff / PAGE_SIZE))
2482 doff -= doff & PAGE_MASK;
2483 /* try to expand write range to include preceding dirty pages */
2484 if (!(doff & PAGE_MASK))
2485 while ((doff > 0) && NBPGDIRTY(bp, (doff - 1) / PAGE_SIZE))
2486 doff -= PAGE_SIZE;
2487 /* if dend page is dirty, move dend to start of next page */
2488 if ((dend & PAGE_MASK) && NBPGDIRTY(bp, dend / PAGE_SIZE))
2489 dend = round_page_32(dend);
2490 /* try to expand write range to include trailing dirty pages */
2491 if (!(dend & PAGE_MASK))
2492 while ((dend < bp->nb_bufsize) && NBPGDIRTY(bp, dend / PAGE_SIZE))
2493 dend += PAGE_SIZE;
2494 /* make sure to keep dend clipped to EOF */
2495 if ((NBOFF(bp) + dend) > (off_t) np->n_size)
2496 dend = np->n_size - NBOFF(bp);
2497 /* calculate range of complete pages being written */
2498 firstpg = round_page_32(doff) / PAGE_SIZE;
2499 lastpg = (trunc_page_32(dend) - 1) / PAGE_SIZE;
2500 /* calculate mask for that page range */
2501 pagemask = ((1 << (lastpg + 1)) - 1) & ~((1 << firstpg) - 1);
91447636 2502
fa4905b1 2503 /*
2d21ac55
A
2504 * compare page mask to nb_dirty; if there are other dirty pages
2505 * then write FILESYNC; otherwise, write UNSTABLE if async and
2506 * not needcommit/stable; otherwise write FILESYNC
fa4905b1 2507 */
2d21ac55
A
2508 if (bp->nb_dirty & ~pagemask)
2509 iomode = NFS_WRITE_FILESYNC;
2510 else if ((bp->nb_flags & (NB_ASYNC | NB_NEEDCOMMIT | NB_STABLE)) == NB_ASYNC)
2511 iomode = NFS_WRITE_UNSTABLE;
2512 else
2513 iomode = NFS_WRITE_FILESYNC;
55e303ae 2514
2d21ac55
A
2515 /* write the whole contiguous dirty range */
2516 bp->nb_offio = doff;
2517 bp->nb_endio = dend;
55e303ae 2518
2d21ac55 2519 OSAddAtomic(1, (SInt32 *)&nfsstats.write_bios);
55e303ae 2520
2d21ac55
A
2521 SET(bp->nb_flags, NB_WRITEINPROG);
2522 error = nfs_buf_write_rpc(bp, iomode, thd, cred);
55e303ae 2523 /*
2d21ac55
A
2524 * For async I/O, the callbacks will finish up the
2525 * write and push out any dirty pages. Otherwise,
2526 * the write has already been finished and any dirty
2527 * pages pushed out.
55e303ae 2528 */
2d21ac55
A
2529 } else {
2530 if (!error && bp->nb_dirty) /* write out any dirty pages */
2531 error = nfs_buf_write_dirty_pages(bp, thd, cred);
2532 nfs_buf_iodone(bp);
2533 }
2534 /* note: bp is still valid only for !async case */
2535out:
2536 if (!async) {
2537 error = nfs_buf_iowait(bp);
2538 /* move to clean list */
2539 if (oldflags & NB_DELWRI) {
2540 lck_mtx_lock(nfs_buf_mutex);
2541 if (bp->nb_vnbufs.le_next != NFSNOLIST)
2542 LIST_REMOVE(bp, nb_vnbufs);
2543 LIST_INSERT_HEAD(&np->n_cleanblkhd, bp, nb_vnbufs);
2544 lck_mtx_unlock(nfs_buf_mutex);
2545 }
2546 FSDBG_BOT(553, bp, NBOFF(bp), bp->nb_flags, error);
2547 nfs_buf_release(bp, 1);
2548 /* check if we need to invalidate (and we can) */
2549 if ((np->n_flag & NNEEDINVALIDATE) &&
2550 !(np->n_bflag & (NBINVALINPROG|NBFLUSHINPROG))) {
2551 int invalidate = 0;
2552 nfs_lock(np, NFS_NODE_LOCK_FORCE);
2553 if (np->n_flag & NNEEDINVALIDATE) {
2554 invalidate = 1;
2555 np->n_flag &= ~NNEEDINVALIDATE;
55e303ae 2556 }
2d21ac55
A
2557 nfs_unlock(np);
2558 if (invalidate) {
2559 /*
2560 * There was a write error and we need to
2561 * invalidate attrs and flush buffers in
2562 * order to sync up with the server.
2563 * (if this write was extending the file,
2564 * we may no longer know the correct size)
2565 *
2566 * But we couldn't call vinvalbuf while holding
2567 * the buffer busy. So we call vinvalbuf() after
2568 * releasing the buffer.
2569 */
2570 nfs_vinvalbuf2(NFSTOV(np), V_SAVE|V_IGNORE_WRITEERR, thd, cred, 1);
55e303ae 2571 }
55e303ae 2572 }
2d21ac55
A
2573 }
2574
2575 if (IS_VALID_CRED(cred))
2576 kauth_cred_unref(&cred);
2577 return (error);
2578}
55e303ae 2579
2d21ac55
A
2580/*
2581 * finish the writing of a buffer
2582 */
2583void
2584nfs_buf_write_finish(struct nfsbuf *bp, thread_t thd, kauth_cred_t cred)
2585{
2586 nfsnode_t np = bp->nb_np;
2587 int error = (bp->nb_flags & NB_ERROR) ? bp->nb_error : 0;
2588 int firstpg, lastpg;
2589 uint32_t pagemask;
2590
2591 if ((error == EINTR) || (error == ERESTART)) {
2592 CLR(bp->nb_flags, NB_ERROR);
2593 SET(bp->nb_flags, NB_EINTR);
2594 }
2595
2596 if (!error) {
2597 /* calculate range of complete pages being written */
2598 firstpg = round_page_32(bp->nb_offio) / PAGE_SIZE;
2599 lastpg = (trunc_page_32(bp->nb_endio) - 1) / PAGE_SIZE;
2600 /* calculate mask for that page range written */
2601 pagemask = ((1 << (lastpg + 1)) - 1) & ~((1 << firstpg) - 1);
2602 /* clear dirty bits for pages we've written */
2603 bp->nb_dirty &= ~pagemask;
2604 }
2605
2606 /* manage needcommit state */
2607 if (!error && (bp->nb_commitlevel == NFS_WRITE_UNSTABLE)) {
2608 if (!ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
2609 nfs_lock(np, NFS_NODE_LOCK_FORCE);
2610 np->n_needcommitcnt++;
2611 nfs_unlock(np);
2612 SET(bp->nb_flags, NB_NEEDCOMMIT);
2613 }
2614 /* make sure nb_dirtyoff/nb_dirtyend reflect actual range written */
2615 bp->nb_dirtyoff = bp->nb_offio;
2616 bp->nb_dirtyend = bp->nb_endio;
2617 } else if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
2618 nfs_lock(np, NFS_NODE_LOCK_FORCE);
2619 np->n_needcommitcnt--;
2620 CHECK_NEEDCOMMITCNT(np);
2621 nfs_unlock(np);
2622 CLR(bp->nb_flags, NB_NEEDCOMMIT);
2623 }
2624
2625 CLR(bp->nb_flags, NB_WRITEINPROG);
2626
2627 /*
2628 * For an unstable write, the buffer is still treated as dirty until
2629 * a commit (or stable (re)write) is performed. Buffers needing only
2630 * a commit are marked with the NB_DELWRI and NB_NEEDCOMMIT flags.
2631 *
2632 * If the write was interrupted we set NB_EINTR. Don't set NB_ERROR
2633 * because that would cause the buffer to be dropped. The buffer is
2634 * still valid and simply needs to be written again.
2635 */
2636 if ((error == EINTR) || (error == ERESTART) || (!error && (bp->nb_flags & NB_NEEDCOMMIT))) {
2637 CLR(bp->nb_flags, NB_INVAL);
2638 if (!ISSET(bp->nb_flags, NB_DELWRI)) {
2639 SET(bp->nb_flags, NB_DELWRI);
2640 lck_mtx_lock(nfs_buf_mutex);
2641 nfs_nbdwrite++;
2642 NFSBUFCNTCHK();
2643 lck_mtx_unlock(nfs_buf_mutex);
2644 }
fa4905b1 2645 /*
2d21ac55
A
2646 * Since for the NB_ASYNC case, we've reassigned the buffer to the
2647 * clean list, we have to reassign it back to the dirty one. Ugh.
fa4905b1 2648 */
2d21ac55
A
2649 if (ISSET(bp->nb_flags, NB_ASYNC)) {
2650 /* move to dirty list */
2651 lck_mtx_lock(nfs_buf_mutex);
2652 if (bp->nb_vnbufs.le_next != NFSNOLIST)
2653 LIST_REMOVE(bp, nb_vnbufs);
2654 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
2655 lck_mtx_unlock(nfs_buf_mutex);
2656 }
2657 } else {
2658 /* either there's an error or we don't need to commit */
2659 if (error) {
2660 /*
2661 * There was a write error and we need to invalidate
2662 * attrs and flush buffers in order to sync up with the
2663 * server. (if this write was extending the file, we
2664 * may no longer know the correct size)
2665 *
2666 * But we can't call vinvalbuf while holding this
2667 * buffer busy. Set a flag to do it after releasing
2668 * the buffer.
2669 */
2670 nfs_lock(np, NFS_NODE_LOCK_FORCE);
2671 np->n_error = error;
2672 np->n_flag |= (NWRITEERR | NNEEDINVALIDATE);
2673 NATTRINVALIDATE(np);
2674 nfs_unlock(np);
2675 }
2676 /* clear the dirty range */
2677 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
2678 }
55e303ae 2679
2d21ac55
A
2680 if (!error && bp->nb_dirty)
2681 nfs_buf_write_dirty_pages(bp, thd, cred);
2682 nfs_buf_iodone(bp);
2683}
fa4905b1 2684
2d21ac55
A
2685/*
2686 * write out any pages marked dirty in a buffer
2687 *
2688 * We do use unstable writes and follow up with a commit.
2689 * If we catch the write verifier changing we'll restart
2690 * do the writes filesync.
2691 */
2692int
2693nfs_buf_write_dirty_pages(struct nfsbuf *bp, thread_t thd, kauth_cred_t cred)
2694{
2695 nfsnode_t np = bp->nb_np;
2696 struct nfsmount *nmp = NFSTONMP(np);
2697 int error = 0, commit, iomode, iomode2, len, pg, count, npages, off;
2698 uint32_t dirty = bp->nb_dirty;
2699 uint64_t wverf;
2700 struct uio uio;
2701 struct iovec_32 io;
55e303ae 2702
2d21ac55
A
2703 if (!bp->nb_dirty)
2704 return (0);
2705
2706 /* there are pages marked dirty that need to be written out */
2707 OSAddAtomic(1, (SInt32 *)&nfsstats.write_bios);
2708 NFS_BUF_MAP(bp);
2709 SET(bp->nb_flags, NB_WRITEINPROG);
2710 npages = bp->nb_bufsize / PAGE_SIZE;
2711 iomode = NFS_WRITE_UNSTABLE;
2712
2713 uio.uio_iovs.iov32p = &io;
2714 uio.uio_iovcnt = 1;
2715 uio.uio_rw = UIO_WRITE;
2716#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
2717 uio.uio_segflg = UIO_SYSSPACE;
2718#else
2719 uio.uio_segflg = UIO_SYSSPACE32;
2720#endif
2721
2722again:
2723 dirty = bp->nb_dirty;
2724 wverf = bp->nb_verf;
2725 commit = NFS_WRITE_FILESYNC;
2726 for (pg = 0; pg < npages; pg++) {
2727 if (!NBPGDIRTY(bp, pg))
2728 continue;
2729 count = 1;
2730 while (((pg + count) < npages) && NBPGDIRTY(bp, pg + count))
2731 count++;
2732 /* write count pages starting with page pg */
2733 off = pg * PAGE_SIZE;
2734 len = count * PAGE_SIZE;
2735 /* clip writes to EOF */
2736 if (NBOFF(bp) + off + len > (off_t) np->n_size)
2737 len -= (NBOFF(bp) + off + len) - np->n_size;
2738 if (len > 0) {
2739 iomode2 = iomode;
2740 io.iov_len = len;
2741 uio_uio_resid_set(&uio, io.iov_len);
2742 uio.uio_offset = NBOFF(bp) + off;
2743 io.iov_base = (uintptr_t) bp->nb_data + off;
2744 error = nfs_write_rpc2(np, &uio, thd, cred, &iomode2, &bp->nb_verf);
2745 if (error)
2746 break;
2747 if (iomode2 < commit) /* Retain the lowest commitment level returned. */
2748 commit = iomode2;
2749 if ((commit != NFS_WRITE_FILESYNC) && (wverf != bp->nb_verf)) {
2750 /* verifier changed, redo all the writes filesync */
2751 iomode = NFS_WRITE_FILESYNC;
2752 goto again;
fa4905b1
A
2753 }
2754 }
2d21ac55
A
2755 /* clear dirty bits */
2756 while (count--) {
2757 dirty &= ~(1 << pg);
2758 if (count) /* leave pg on last page */
2759 pg++;
2760 }
2761 }
2762 CLR(bp->nb_flags, NB_WRITEINPROG);
2763
2764 if (!error && (commit != NFS_WRITE_FILESYNC)) {
2765 error = nmp->nm_funcs->nf_commit_rpc(np, NBOFF(bp), bp->nb_bufsize, cred);
2766 if (error == NFSERR_STALEWRITEVERF) {
2767 /* verifier changed, so we need to restart all the writes */
2768 iomode = NFS_WRITE_FILESYNC;
2769 goto again;
2770 }
2771 }
2772 if (!error) {
2773 bp->nb_dirty = dirty;
2774 } else {
2775 SET(bp->nb_flags, NB_ERROR);
2776 bp->nb_error = error;
2777 }
2778 return (error);
2779}
2780
2781/*
2782 * initiate the NFS WRITE RPC(s) for a buffer
2783 */
2784int
2785nfs_buf_write_rpc(struct nfsbuf *bp, int iomode, thread_t thd, kauth_cred_t cred)
2786{
2787 struct nfsmount *nmp;
2788 nfsnode_t np = bp->nb_np;
2789 int error = 0, nfsvers, async;
2790 int offset, length, nmwsize, nrpcs, len;
2791 struct nfsreq *req;
2792 struct nfsreq_cbinfo cb;
2793 struct uio uio;
2794 struct iovec_32 io;
2795
2796 nmp = NFSTONMP(np);
2797 if (!nmp) {
2798 bp->nb_error = error = ENXIO;
2799 SET(bp->nb_flags, NB_ERROR);
2800 nfs_buf_iodone(bp);
2801 return (error);
2802 }
2803 nfsvers = nmp->nm_vers;
2804 nmwsize = nmp->nm_wsize;
2805
2806 offset = bp->nb_offio;
2807 length = bp->nb_endio - bp->nb_offio;
2808
2809 /* Note: Can only do async I/O if nfsiods are configured. */
2810 async = (bp->nb_flags & NB_ASYNC) && (NFSIOD_MAX > 0);
2811 bp->nb_commitlevel = NFS_WRITE_FILESYNC;
2812 cb.rcb_func = async ? nfs_buf_write_rpc_finish : NULL;
2813 cb.rcb_bp = bp;
2814
2815 if ((nfsvers == NFS_VER2) && ((NBOFF(bp) + bp->nb_endio) > 0xffffffffLL)) {
2816 bp->nb_error = error = EFBIG;
2817 SET(bp->nb_flags, NB_ERROR);
2818 nfs_buf_iodone(bp);
2819 return (error);
2820 }
2821
2822 uio.uio_iovs.iov32p = &io;
2823 uio.uio_iovcnt = 1;
2824 uio.uio_rw = UIO_WRITE;
2825#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
2826 uio.uio_segflg = UIO_SYSSPACE;
2827#else
2828 uio.uio_segflg = UIO_SYSSPACE32;
2829#endif
2830 io.iov_len = length;
2831 uio_uio_resid_set(&uio, io.iov_len);
2832 uio.uio_offset = NBOFF(bp) + offset;
2833 io.iov_base = (uintptr_t) bp->nb_data + offset;
2834
2835 bp->nb_rpcs = nrpcs = (length + nmwsize - 1) / nmwsize;
2836 if (async && (nrpcs > 1)) {
2837 SET(bp->nb_flags, NB_MULTASYNCRPC);
2838 } else {
2839 CLR(bp->nb_flags, NB_MULTASYNCRPC);
2840 }
2841
2842 while (length > 0) {
2843 if (ISSET(bp->nb_flags, NB_ERROR)) {
2844 error = bp->nb_error;
2845 break;
2846 }
2847 len = (length > nmwsize) ? nmwsize : length;
2848 cb.rcb_args[0] = offset;
2849 cb.rcb_args[1] = len;
2850 if (async && ((error = nfs_async_write_start(nmp))))
2851 break;
2852 req = NULL;
2853 error = nmp->nm_funcs->nf_write_rpc_async(np, &uio, len, thd, cred,
2854 iomode, &cb, &req);
2855 if (error) {
2856 if (async)
2857 nfs_async_write_done(nmp);
2858 break;
2859 }
2860 offset += len;
2861 length -= len;
2862 if (async)
2863 continue;
2864 nfs_buf_write_rpc_finish(req);
2865 }
2866
2867 if (length > 0) {
fa4905b1 2868 /*
2d21ac55
A
2869 * Something bad happened while trying to send the RPCs.
2870 * Wait for any outstanding requests to complete.
fa4905b1 2871 */
2d21ac55
A
2872 bp->nb_error = error;
2873 SET(bp->nb_flags, NB_ERROR);
2874 if (ISSET(bp->nb_flags, NB_MULTASYNCRPC)) {
2875 nrpcs = (length + nmwsize - 1) / nmwsize;
2876 lck_mtx_lock(nfs_buf_mutex);
2877 bp->nb_rpcs -= nrpcs;
2878 if (bp->nb_rpcs == 0) {
2879 /* No RPCs left, so the buffer's done */
2880 lck_mtx_unlock(nfs_buf_mutex);
2881 nfs_buf_write_finish(bp, thd, cred);
2882 } else {
2883 /* wait for the last RPC to mark it done */
2884 while (bp->nb_rpcs > 0)
2885 msleep(&bp->nb_rpcs, nfs_buf_mutex, 0,
2886 "nfs_buf_write_rpc_cancel", NULL);
2887 lck_mtx_unlock(nfs_buf_mutex);
fa4905b1 2888 }
2d21ac55
A
2889 } else {
2890 nfs_buf_write_finish(bp, thd, cred);
2891 }
2892 }
55e303ae 2893
2d21ac55
A
2894 return (error);
2895}
2896
2897/*
2898 * finish up an NFS WRITE RPC on a buffer
2899 */
2900void
2901nfs_buf_write_rpc_finish(struct nfsreq *req)
2902{
2903 int error = 0, nfsvers, offset, length, multasyncrpc, finished;
2904 int committed = NFS_WRITE_FILESYNC;
2905 uint64_t wverf = 0;
2906 size_t rlen;
2907 void *wakeme = NULL;
2908 struct nfsreq_cbinfo cb;
2909 struct nfsreq *wreq = NULL;
2910 struct nfsbuf *bp;
2911 struct nfsmount *nmp;
2912 nfsnode_t np;
2913 thread_t thd;
2914 kauth_cred_t cred;
2915 struct uio uio;
2916 struct iovec_32 io;
2917
2918finish:
2919 np = req->r_np;
2920 thd = req->r_thread;
2921 cred = req->r_cred;
2922 if (IS_VALID_CRED(cred))
2923 kauth_cred_ref(cred);
2924 cb = req->r_callback;
2925 bp = cb.rcb_bp;
2926
2927 nmp = NFSTONMP(np);
2928 if (!nmp) {
2929 SET(bp->nb_flags, NB_ERROR);
2930 bp->nb_error = error = ENXIO;
2931 }
2932 if (error || ISSET(bp->nb_flags, NB_ERROR)) {
2933 /* just drop it */
2934 nfs_request_async_cancel(req);
2935 goto out;
2936 }
2937 nfsvers = nmp->nm_vers;
2938
2939 offset = cb.rcb_args[0];
2940 rlen = length = cb.rcb_args[1];
2941
2942 /* finish the RPC */
2943 error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req, &committed, &rlen, &wverf);
2944 if ((error == EINPROGRESS) && cb.rcb_func) {
2945 /* async request restarted */
2946 if (IS_VALID_CRED(cred))
2947 kauth_cred_unref(&cred);
2948 return;
2949 }
2950
2951 if (error) {
2952 SET(bp->nb_flags, NB_ERROR);
2953 bp->nb_error = error;
2954 }
2955 if (error || (nfsvers == NFS_VER2))
2956 goto out;
2957 if (rlen <= 0) {
2958 SET(bp->nb_flags, NB_ERROR);
2959 bp->nb_error = error = EIO;
2960 goto out;
2961 }
2962
2963 /* save lowest commit level returned */
2964 if (committed < bp->nb_commitlevel)
2965 bp->nb_commitlevel = committed;
2966
2967 /* check the write verifier */
2968 if (!bp->nb_verf) {
2969 bp->nb_verf = wverf;
2970 } else if (bp->nb_verf != wverf) {
2971 /* verifier changed, so buffer will need to be rewritten */
2972 bp->nb_flags |= NB_STALEWVERF;
2973 bp->nb_commitlevel = NFS_WRITE_UNSTABLE;
2974 bp->nb_verf = wverf;
2975 }
2976
2977 /*
2978 * check for a short write
2979 *
2980 * If the server didn't write all the data, then we
2981 * need to issue another write for the rest of it.
2982 * (Don't bother if the buffer hit an error or stale wverf.)
2983 */
2984 if (((int)rlen < length) && !(bp->nb_flags & (NB_STALEWVERF|NB_ERROR))) {
2985 offset += rlen;
2986 length -= rlen;
2987
2988 uio.uio_iovs.iov32p = &io;
2989 uio.uio_iovcnt = 1;
2990 uio.uio_rw = UIO_WRITE;
91447636 2991#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
2d21ac55 2992 uio.uio_segflg = UIO_SYSSPACE;
91447636 2993#else
2d21ac55
A
2994 uio.uio_segflg = UIO_SYSSPACE32;
2995#endif
2996 io.iov_len = length;
2997 uio_uio_resid_set(&uio, io.iov_len);
2998 uio.uio_offset = NBOFF(bp) + offset;
2999 io.iov_base = (uintptr_t) bp->nb_data + offset;
55e303ae 3000
2d21ac55
A
3001 cb.rcb_args[0] = offset;
3002 cb.rcb_args[1] = length;
55e303ae 3003
2d21ac55
A
3004 error = nmp->nm_funcs->nf_write_rpc_async(np, &uio, length, thd, cred,
3005 NFS_WRITE_FILESYNC, &cb, &wreq);
3006 if (!error) {
3007 if (IS_VALID_CRED(cred))
3008 kauth_cred_unref(&cred);
3009 if (!cb.rcb_func) {
3010 /* if !async we'll need to wait for this RPC to finish */
3011 req = wreq;
3012 goto finish;
fa4905b1 3013 }
2d21ac55
A
3014 /*
3015 * We're done here.
3016 * Outstanding RPC count is unchanged.
3017 * Callback will be called when RPC is done.
3018 */
3019 return;
fa4905b1 3020 }
2d21ac55
A
3021 SET(bp->nb_flags, NB_ERROR);
3022 bp->nb_error = error;
3023 }
55e303ae 3024
2d21ac55
A
3025out:
3026 if (cb.rcb_func)
3027 nfs_async_write_done(nmp);
3028 /*
3029 * Decrement outstanding RPC count on buffer
3030 * and call nfs_buf_write_finish on last RPC.
3031 *
3032 * (Note: when there are multiple async RPCs issued for a
3033 * buffer we need nfs_buffer_mutex to avoid problems when
3034 * aborting a partially-initiated set of RPCs)
3035 */
3036 multasyncrpc = ISSET(bp->nb_flags, NB_MULTASYNCRPC);
3037 if (multasyncrpc)
3038 lck_mtx_lock(nfs_buf_mutex);
3039
3040 bp->nb_rpcs--;
3041 finished = (bp->nb_rpcs == 0);
55e303ae 3042
2d21ac55
A
3043 if (multasyncrpc)
3044 lck_mtx_unlock(nfs_buf_mutex);
3045
3046 if (finished) {
3047 if (multasyncrpc)
3048 wakeme = &bp->nb_rpcs;
3049 nfs_buf_write_finish(bp, thd, cred);
3050 if (wakeme)
3051 wakeup(wakeme);
3052 }
3053
3054 if (IS_VALID_CRED(cred))
3055 kauth_cred_unref(&cred);
3056}
3057
3058/*
3059 * Send commit(s) for the given node's "needcommit" buffers
3060 */
3061int
3062nfs_flushcommits(nfsnode_t np, int nowait)
3063{
3064 struct nfsmount *nmp;
3065 struct nfsbuf *bp;
3066 struct nfsbuflists blist, commitlist;
3067 int error = 0, retv, wcred_set, flags, dirty;
3068 u_quad_t off, endoff, toff;
3069 u_int32_t count;
3070 kauth_cred_t wcred = NULL;
3071
3072 FSDBG_TOP(557, np, 0, 0, 0);
3073
3074 /*
3075 * A nb_flags == (NB_DELWRI | NB_NEEDCOMMIT) block has been written to the
3076 * server, but nas not been committed to stable storage on the server
3077 * yet. The byte range is worked out for as many nfsbufs as we can handle
3078 * and the commit rpc is done.
3079 */
3080 if (!LIST_EMPTY(&np->n_dirtyblkhd)) {
3081 error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
3082 if (error)
3083 goto done;
1c79356b 3084 np->n_flag |= NMODIFIED;
2d21ac55
A
3085 nfs_unlock(np);
3086 }
1c79356b 3087
2d21ac55
A
3088 off = (u_quad_t)-1;
3089 endoff = 0;
3090 wcred_set = 0;
3091 LIST_INIT(&commitlist);
3092
3093 nmp = NFSTONMP(np);
3094 if (!nmp) {
3095 error = ENXIO;
3096 goto done;
3097 }
3098 if (nmp->nm_vers == NFS_VER2) {
3099 error = EINVAL;
3100 goto done;
3101 }
3102
3103 flags = NBI_DIRTY;
3104 if (nowait)
3105 flags |= NBI_NOWAIT;
3106 lck_mtx_lock(nfs_buf_mutex);
3107 if (!nfs_buf_iterprepare(np, &blist, flags)) {
3108 while ((bp = LIST_FIRST(&blist))) {
3109 LIST_REMOVE(bp, nb_vnbufs);
3110 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
3111 error = nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0);
3112 if (error)
3113 continue;
3114 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT))
3115 nfs_buf_check_write_verifier(np, bp);
3116 if (((bp->nb_flags & (NB_DELWRI | NB_NEEDCOMMIT))
3117 != (NB_DELWRI | NB_NEEDCOMMIT))) {
3118 nfs_buf_drop(bp);
3119 continue;
3120 }
3121 nfs_buf_remfree(bp);
3122 lck_mtx_unlock(nfs_buf_mutex);
3123 /*
3124 * we need a upl to see if the page has been
3125 * dirtied (think mmap) since the unstable write, and
3126 * also to prevent vm from paging it during our commit rpc
3127 */
3128 if (!ISSET(bp->nb_flags, NB_PAGELIST)) {
3129 retv = nfs_buf_upl_setup(bp);
3130 if (retv) {
3131 /* unable to create upl */
3132 /* vm object must no longer exist */
3133 /* this could be fatal if we need */
3134 /* to write the data again, we'll see... */
3135 printf("nfs_flushcommits: upl create failed %d\n", retv);
3136 bp->nb_valid = bp->nb_dirty = 0;
3137 }
3138 }
3139 nfs_buf_upl_check(bp);
3140 lck_mtx_lock(nfs_buf_mutex);
3141
3142 FSDBG(557, bp, bp->nb_flags, bp->nb_valid, bp->nb_dirty);
3143 FSDBG(557, bp->nb_validoff, bp->nb_validend,
3144 bp->nb_dirtyoff, bp->nb_dirtyend);
55e303ae 3145
55e303ae 3146 /*
2d21ac55
A
3147 * We used to check for dirty pages here; if there were any
3148 * we'd abort the commit and force the entire buffer to be
3149 * written again.
3150 *
3151 * Instead of doing that, we now go ahead and commit the dirty
3152 * range, and then leave the buffer around with dirty pages
3153 * that will be written out later.
55e303ae 3154 */
2d21ac55
A
3155
3156 /*
3157 * Work out if all buffers are using the same cred
3158 * so we can deal with them all with one commit.
3159 *
3160 * Note: creds in bp's must be obtained by kauth_cred_ref
3161 * on the same original cred in order for them to be equal.
3162 */
3163 if (wcred_set == 0) {
3164 wcred = bp->nb_wcred;
3165 if (!IS_VALID_CRED(wcred))
3166 panic("nfs: needcommit w/out wcred");
3167 wcred_set = 1;
3168 } else if ((wcred_set == 1) && wcred != bp->nb_wcred) {
3169 wcred_set = -1;
3170 }
3171 SET(bp->nb_flags, NB_WRITEINPROG);
3172
3173 /*
3174 * A list of these buffers is kept so that the
3175 * second loop knows which buffers have actually
3176 * been committed. This is necessary, since there
3177 * may be a race between the commit rpc and new
3178 * uncommitted writes on the file.
3179 */
3180 LIST_REMOVE(bp, nb_vnbufs);
3181 LIST_INSERT_HEAD(&commitlist, bp, nb_vnbufs);
3182 toff = NBOFF(bp) + bp->nb_dirtyoff;
3183 if (toff < off)
3184 off = toff;
3185 toff += (u_quad_t)(bp->nb_dirtyend - bp->nb_dirtyoff);
3186 if (toff > endoff)
3187 endoff = toff;
3188 }
3189 nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
3190 }
3191 lck_mtx_unlock(nfs_buf_mutex);
3192
3193 if (LIST_EMPTY(&commitlist)) {
3194 error = ENOBUFS;
3195 goto done;
3196 }
3197
3198 /*
3199 * Commit data on the server, as required.
3200 * If all bufs are using the same wcred, then use that with
3201 * one call for all of them, otherwise commit each one
3202 * separately.
3203 */
3204 if (wcred_set == 1) {
3205 /*
3206 * Note, it's possible the commit range could be >2^32-1.
3207 * If it is, we'll send one commit that covers the whole file.
3208 */
3209 if ((endoff - off) > 0xffffffff)
3210 count = 0;
3211 else
3212 count = (endoff - off);
3213 retv = nmp->nm_funcs->nf_commit_rpc(np, off, count, wcred);
3214 } else {
3215 retv = 0;
3216 LIST_FOREACH(bp, &commitlist, nb_vnbufs) {
3217 toff = NBOFF(bp) + bp->nb_dirtyoff;
3218 count = bp->nb_dirtyend - bp->nb_dirtyoff;
3219 retv = nmp->nm_funcs->nf_commit_rpc(np, toff, count, bp->nb_wcred);
3220 if (retv)
3221 break;
55e303ae 3222 }
2d21ac55
A
3223 }
3224
3225 /*
3226 * Now, either mark the blocks I/O done or mark the
3227 * blocks dirty, depending on whether the commit
3228 * succeeded.
3229 */
3230 while ((bp = LIST_FIRST(&commitlist))) {
3231 LIST_REMOVE(bp, nb_vnbufs);
3232 FSDBG(557, bp, retv, bp->nb_flags, bp->nb_dirty);
3233 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3234 CLR(bp->nb_flags, (NB_NEEDCOMMIT | NB_WRITEINPROG));
3235 np->n_needcommitcnt--;
3236 CHECK_NEEDCOMMITCNT(np);
3237 nfs_unlock(np);
3238
3239 if (retv) {
3240 /* move back to dirty list */
3241 lck_mtx_lock(nfs_buf_mutex);
3242 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
3243 lck_mtx_unlock(nfs_buf_mutex);
3244 nfs_buf_release(bp, 1);
3245 continue;
1c79356b 3246 }
2d21ac55
A
3247
3248 vnode_startwrite(NFSTOV(np));
3249 if (ISSET(bp->nb_flags, NB_DELWRI)) {
3250 lck_mtx_lock(nfs_buf_mutex);
3251 nfs_nbdwrite--;
3252 NFSBUFCNTCHK();
3253 lck_mtx_unlock(nfs_buf_mutex);
3254 wakeup(&nfs_nbdwrite);
1c79356b 3255 }
2d21ac55
A
3256 CLR(bp->nb_flags, (NB_READ|NB_DONE|NB_ERROR|NB_DELWRI));
3257 /* if block still has dirty pages, we don't want it to */
3258 /* be released in nfs_buf_iodone(). So, don't set NB_ASYNC. */
3259 if (!(dirty = bp->nb_dirty))
3260 SET(bp->nb_flags, NB_ASYNC);
3261 else
3262 CLR(bp->nb_flags, NB_ASYNC);
1c79356b 3263
2d21ac55
A
3264 /* move to clean list */
3265 lck_mtx_lock(nfs_buf_mutex);
3266 LIST_INSERT_HEAD(&np->n_cleanblkhd, bp, nb_vnbufs);
3267 lck_mtx_unlock(nfs_buf_mutex);
3268
3269 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
3270
3271 nfs_buf_iodone(bp);
3272 if (dirty) {
3273 /* throw it back in as a delayed write buffer */
3274 CLR(bp->nb_flags, NB_DONE);
3275 nfs_buf_write_delayed(bp);
55e303ae 3276 }
2d21ac55 3277 }
1c79356b 3278
2d21ac55
A
3279done:
3280 FSDBG_BOT(557, np, 0, 0, error);
3281 return (error);
3282}
3283
3284/*
3285 * Flush all the blocks associated with a vnode.
3286 * Walk through the buffer pool and push any dirty pages
3287 * associated with the vnode.
3288 */
3289int
3290nfs_flush(nfsnode_t np, int waitfor, thread_t thd, int ignore_writeerr)
3291{
3292 struct nfsbuf *bp;
3293 struct nfsbuflists blist;
3294 struct nfsmount *nmp = NFSTONMP(np);
3295 int error = 0, error2, slptimeo = 0, slpflag = 0;
3296 int nfsvers, flags, passone = 1;
3297
3298 FSDBG_TOP(517, np, waitfor, ignore_writeerr, 0);
3299
3300 if (!nmp) {
3301 error = ENXIO;
3302 goto out;
3303 }
3304 nfsvers = nmp->nm_vers;
3305 if (nmp->nm_flag & NFSMNT_INT)
3306 slpflag = PCATCH;
3307
3308 if (!LIST_EMPTY(&np->n_dirtyblkhd)) {
3309 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3310 np->n_flag |= NMODIFIED;
3311 nfs_unlock(np);
3312 }
3313
3314 lck_mtx_lock(nfs_buf_mutex);
3315 while (np->n_bflag & NBFLUSHINPROG) {
3316 np->n_bflag |= NBFLUSHWANT;
3317 error = msleep(&np->n_bflag, nfs_buf_mutex, slpflag, "nfs_flush", NULL);
3318 if (error) {
3319 lck_mtx_unlock(nfs_buf_mutex);
3320 goto out;
3321 }
3322 }
3323 np->n_bflag |= NBFLUSHINPROG;
3324
3325 /*
3326 * On the first pass, start async/unstable writes on all
3327 * delayed write buffers. Then wait for all writes to complete
3328 * and call nfs_flushcommits() to commit any uncommitted buffers.
3329 * On all subsequent passes, start STABLE writes on any remaining
3330 * dirty buffers. Then wait for all writes to complete.
3331 */
3332again:
3333 FSDBG(518, LIST_FIRST(&np->n_dirtyblkhd), np->n_flag, 0, 0);
3334 if (!NFSTONMP(np)) {
3335 lck_mtx_unlock(nfs_buf_mutex);
3336 error = ENXIO;
3337 goto done;
3338 }
3339
3340 /* Start/do any write(s) that are required. */
3341 if (!nfs_buf_iterprepare(np, &blist, NBI_DIRTY)) {
3342 while ((bp = LIST_FIRST(&blist))) {
3343 LIST_REMOVE(bp, nb_vnbufs);
3344 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
3345 flags = (passone || (waitfor != MNT_WAIT)) ? NBAC_NOWAIT : 0;
3346 if (flags != NBAC_NOWAIT)
3347 nfs_buf_refget(bp);
3348 while ((error = nfs_buf_acquire(bp, flags, slpflag, slptimeo))) {
3349 FSDBG(524, bp, flags, bp->nb_lflags, bp->nb_flags);
3350 if (error == EBUSY)
3351 break;
3352 if (error) {
3353 error2 = nfs_sigintr(NFSTONMP(np), NULL, thd, 0);
3354 if (error2) {
3355 if (flags != NBAC_NOWAIT)
3356 nfs_buf_refrele(bp);
3357 nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
3358 lck_mtx_unlock(nfs_buf_mutex);
3359 error = error2;
3360 goto done;
3361 }
3362 if (slpflag == PCATCH) {
3363 slpflag = 0;
3364 slptimeo = 2 * hz;
3365 }
3366 }
3367 }
3368 if (flags != NBAC_NOWAIT)
3369 nfs_buf_refrele(bp);
3370 if (error == EBUSY)
3371 continue;
3372 if (!bp->nb_np) {
3373 /* buffer is no longer valid */
3374 nfs_buf_drop(bp);
3375 continue;
3376 }
3377 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT))
3378 nfs_buf_check_write_verifier(np, bp);
3379 if (!ISSET(bp->nb_flags, NB_DELWRI)) {
3380 /* buffer is no longer dirty */
3381 nfs_buf_drop(bp);
3382 continue;
3383 }
3384 FSDBG(525, bp, passone, bp->nb_lflags, bp->nb_flags);
3385 if ((passone || (waitfor != MNT_WAIT)) &&
3386 ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
3387 nfs_buf_drop(bp);
3388 continue;
3389 }
3390 nfs_buf_remfree(bp);
3391 lck_mtx_unlock(nfs_buf_mutex);
3392 if (ISSET(bp->nb_flags, NB_ERROR)) {
3393 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3394 np->n_error = bp->nb_error ? bp->nb_error : EIO;
3395 np->n_flag |= NWRITEERR;
3396 nfs_unlock(np);
3397 nfs_buf_release(bp, 1);
3398 lck_mtx_lock(nfs_buf_mutex);
3399 continue;
3400 }
3401 SET(bp->nb_flags, NB_ASYNC);
3402 if (!passone) {
3403 /* NB_STABLE forces this to be written FILESYNC */
3404 SET(bp->nb_flags, NB_STABLE);
3405 }
3406 nfs_buf_write(bp);
3407 lck_mtx_lock(nfs_buf_mutex);
3408 }
3409 nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
3410 }
3411 lck_mtx_unlock(nfs_buf_mutex);
3412
3413 if (waitfor == MNT_WAIT) {
3414 while ((error = vnode_waitforwrites(NFSTOV(np), 0, slpflag, slptimeo, "nfsflush"))) {
3415 error2 = nfs_sigintr(NFSTONMP(np), NULL, thd, 0);
3416 if (error2) {
3417 error = error2;
3418 goto done;
3419 }
3420 if (slpflag == PCATCH) {
3421 slpflag = 0;
3422 slptimeo = 2 * hz;
55e303ae 3423 }
2d21ac55
A
3424 }
3425 }
55e303ae 3426
2d21ac55
A
3427 if (nfsvers != NFS_VER2) {
3428 /* loop while it looks like there are still buffers to be */
3429 /* commited and nfs_flushcommits() seems to be handling them. */
3430 while (np->n_needcommitcnt)
3431 if (nfs_flushcommits(np, 0))
3432 break;
3433 }
55e303ae 3434
2d21ac55
A
3435 if (passone) {
3436 passone = 0;
3437 if (!LIST_EMPTY(&np->n_dirtyblkhd)) {
3438 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3439 np->n_flag |= NMODIFIED;
3440 nfs_unlock(np);
3441 }
3442 lck_mtx_lock(nfs_buf_mutex);
3443 goto again;
3444 }
55e303ae 3445
2d21ac55
A
3446 if (waitfor == MNT_WAIT) {
3447 if (!LIST_EMPTY(&np->n_dirtyblkhd)) {
3448 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3449 np->n_flag |= NMODIFIED;
3450 nfs_unlock(np);
3451 }
3452 lck_mtx_lock(nfs_buf_mutex);
3453 if (!LIST_EMPTY(&np->n_dirtyblkhd))
3454 goto again;
3455 lck_mtx_unlock(nfs_buf_mutex);
3456 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3457 /* if we have no dirty blocks, we can clear the modified flag */
3458 if (!np->n_wrbusy)
3459 np->n_flag &= ~NMODIFIED;
3460 } else {
3461 nfs_lock(np, NFS_NODE_LOCK_FORCE);
0c530ab8
A
3462 }
3463
2d21ac55
A
3464 FSDBG(526, np->n_flag, np->n_error, 0, 0);
3465 if (!ignore_writeerr && (np->n_flag & NWRITEERR)) {
3466 error = np->n_error;
3467 np->n_flag &= ~NWRITEERR;
3468 }
3469 nfs_unlock(np);
3470done:
3471 lck_mtx_lock(nfs_buf_mutex);
3472 flags = np->n_bflag;
3473 np->n_bflag &= ~(NBFLUSHINPROG|NBFLUSHWANT);
3474 lck_mtx_unlock(nfs_buf_mutex);
3475 if (flags & NBFLUSHWANT)
3476 wakeup(&np->n_bflag);
3477out:
3478 FSDBG_BOT(517, np, error, ignore_writeerr, 0);
0c530ab8 3479 return (error);
1c79356b
A
3480}
3481
1c79356b 3482/*
55e303ae
A
3483 * Flush out and invalidate all buffers associated with a vnode.
3484 * Called with the underlying object locked.
1c79356b 3485 */
55e303ae 3486static int
91447636 3487nfs_vinvalbuf_internal(
2d21ac55 3488 nfsnode_t np,
91447636 3489 int flags,
2d21ac55 3490 thread_t thd,
91447636 3491 kauth_cred_t cred,
91447636
A
3492 int slpflag,
3493 int slptimeo)
1c79356b 3494{
55e303ae 3495 struct nfsbuf *bp;
91447636
A
3496 struct nfsbuflists blist;
3497 int list, error = 0;
9bccf70c 3498
55e303ae 3499 if (flags & V_SAVE) {
2d21ac55 3500 if ((error = nfs_flush(np, MNT_WAIT, thd, (flags & V_IGNORE_WRITEERR))))
55e303ae 3501 return (error);
9bccf70c
A
3502 }
3503
91447636 3504 lck_mtx_lock(nfs_buf_mutex);
55e303ae 3505 for (;;) {
91447636
A
3506 list = NBI_CLEAN;
3507 if (nfs_buf_iterprepare(np, &blist, list)) {
3508 list = NBI_DIRTY;
3509 if (nfs_buf_iterprepare(np, &blist, list))
3510 break;
3511 }
3512 while ((bp = LIST_FIRST(&blist))) {
3513 LIST_REMOVE(bp, nb_vnbufs);
3514 if (list == NBI_CLEAN)
3515 LIST_INSERT_HEAD(&np->n_cleanblkhd, bp, nb_vnbufs);
3516 else
3517 LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
3518 nfs_buf_refget(bp);
3519 while ((error = nfs_buf_acquire(bp, NBAC_REMOVE, slpflag, slptimeo))) {
2d21ac55 3520 FSDBG(556, np, bp, NBOFF(bp), bp->nb_flags);
91447636 3521 if (error != EAGAIN) {
2d21ac55 3522 FSDBG(554, np, bp, -1, error);
91447636
A
3523 nfs_buf_refrele(bp);
3524 nfs_buf_itercomplete(np, &blist, list);
3525 lck_mtx_unlock(nfs_buf_mutex);
55e303ae
A
3526 return (error);
3527 }
55e303ae 3528 }
91447636 3529 nfs_buf_refrele(bp);
2d21ac55 3530 FSDBG(554, np, bp, NBOFF(bp), bp->nb_flags);
91447636 3531 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55 3532 if ((flags & V_SAVE) && UBCINFOEXISTS(NFSTOV(np)) && bp->nb_np &&
91447636 3533 (NBOFF(bp) < (off_t)np->n_size)) {
2d21ac55 3534 /* extra paranoia: make sure we're not */
55e303ae
A
3535 /* somehow leaving any dirty data around */
3536 int mustwrite = 0;
91447636
A
3537 int end = (NBOFF(bp) + bp->nb_bufsize > (off_t)np->n_size) ?
3538 ((off_t)np->n_size - NBOFF(bp)) : bp->nb_bufsize;
55e303ae
A
3539 if (!ISSET(bp->nb_flags, NB_PAGELIST)) {
3540 error = nfs_buf_upl_setup(bp);
3541 if (error == EINVAL) {
3542 /* vm object must no longer exist */
3543 /* hopefully we don't need to do */
3544 /* anything for this buffer */
3545 } else if (error)
91447636 3546 printf("nfs_vinvalbuf: upl setup failed %d\n", error);
55e303ae
A
3547 bp->nb_valid = bp->nb_dirty = 0;
3548 }
3549 nfs_buf_upl_check(bp);
3550 /* check for any dirty data before the EOF */
2d21ac55 3551 if ((bp->nb_dirtyend > 0) && (bp->nb_dirtyoff < end)) {
55e303ae 3552 /* clip dirty range to EOF */
2d21ac55 3553 if (bp->nb_dirtyend > end) {
55e303ae 3554 bp->nb_dirtyend = end;
2d21ac55
A
3555 if (bp->nb_dirtyoff >= bp->nb_dirtyend)
3556 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
3557 }
3558 if ((bp->nb_dirtyend > 0) && (bp->nb_dirtyoff < end))
3559 mustwrite++;
55e303ae
A
3560 }
3561 bp->nb_dirty &= (1 << (round_page_32(end)/PAGE_SIZE)) - 1;
2d21ac55
A
3562 if (bp->nb_dirty)
3563 mustwrite++;
91447636 3564 /* also make sure we'll have a credential to do the write */
0c530ab8 3565 if (mustwrite && !IS_VALID_CRED(bp->nb_wcred) && !IS_VALID_CRED(cred)) {
91447636
A
3566 printf("nfs_vinvalbuf: found dirty buffer with no write creds\n");
3567 mustwrite = 0;
3568 }
55e303ae 3569 if (mustwrite) {
2d21ac55 3570 FSDBG(554, np, bp, 0xd00dee, bp->nb_flags);
55e303ae
A
3571 if (!ISSET(bp->nb_flags, NB_PAGELIST))
3572 panic("nfs_vinvalbuf: dirty buffer without upl");
3573 /* gotta write out dirty data before invalidating */
3574 /* (NB_STABLE indicates that data writes should be FILESYNC) */
3575 /* (NB_NOCACHE indicates buffer should be discarded) */
3576 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL | NB_ASYNC));
3577 SET(bp->nb_flags, NB_STABLE | NB_NOCACHE);
0c530ab8 3578 if (!IS_VALID_CRED(bp->nb_wcred)) {
91447636
A
3579 kauth_cred_ref(cred);
3580 bp->nb_wcred = cred;
3581 }
55e303ae
A
3582 error = nfs_buf_write(bp);
3583 // Note: bp has been released
3584 if (error) {
3585 FSDBG(554, bp, 0xd00dee, 0xbad, error);
2d21ac55 3586 nfs_lock(np, NFS_NODE_LOCK_FORCE);
55e303ae
A
3587 np->n_error = error;
3588 np->n_flag |= NWRITEERR;
2d21ac55 3589 nfs_unlock(np);
91447636
A
3590 /*
3591 * There was a write error and we need to
3592 * invalidate attrs to sync with server.
3593 * (if this write was extending the file,
3594 * we may no longer know the correct size)
3595 */
3596 NATTRINVALIDATE(np);
55e303ae
A
3597 error = 0;
3598 }
91447636
A
3599 lck_mtx_lock(nfs_buf_mutex);
3600 continue;
55e303ae
A
3601 }
3602 }
3603 SET(bp->nb_flags, NB_INVAL);
91447636 3604 // hold off on FREEUPs until we're done here
483a1d10 3605 nfs_buf_release(bp, 0);
91447636 3606 lck_mtx_lock(nfs_buf_mutex);
55e303ae 3607 }
91447636 3608 nfs_buf_itercomplete(np, &blist, list);
55e303ae 3609 }
2d21ac55
A
3610 if (!LIST_EMPTY(&(np)->n_dirtyblkhd) || !LIST_EMPTY(&(np)->n_cleanblkhd))
3611 panic("nfs_vinvalbuf: flush/inval failed");
91447636 3612 lck_mtx_unlock(nfs_buf_mutex);
2d21ac55
A
3613 if (!(flags & V_SAVE)) {
3614 nfs_lock(np, NFS_NODE_LOCK_FORCE);
3615 np->n_flag &= ~NMODIFIED;
3616 nfs_unlock(np);
3617 }
483a1d10 3618 NFS_BUF_FREEUP();
55e303ae 3619 return (0);
1c79356b
A
3620}
3621
55e303ae 3622
1c79356b
A
3623/*
3624 * Flush and invalidate all dirty buffers. If another process is already
3625 * doing the flush, just wait for completion.
3626 */
3627int
2d21ac55
A
3628nfs_vinvalbuf(vnode_t vp, int flags, vfs_context_t ctx, int intrflg)
3629{
3630 return nfs_vinvalbuf2(vp, flags, vfs_context_thread(ctx), vfs_context_ucred(ctx), intrflg);
3631}
3632
3633int
3634nfs_vinvalbuf2(vnode_t vp, int flags, thread_t thd, kauth_cred_t cred, int intrflg)
1c79356b 3635{
2d21ac55
A
3636 nfsnode_t np = VTONFS(vp);
3637 struct nfsmount *nmp = VTONMP(vp);
3638 int error, rv, slpflag, slptimeo, nflags;
91447636 3639 off_t size;
1c79356b 3640
2d21ac55 3641 FSDBG_TOP(554, np, flags, intrflg, 0);
55e303ae 3642
2d21ac55 3643 if (nmp && !(nmp->nm_flag & NFSMNT_INT))
1c79356b
A
3644 intrflg = 0;
3645 if (intrflg) {
3646 slpflag = PCATCH;
3647 slptimeo = 2 * hz;
3648 } else {
3649 slpflag = 0;
3650 slptimeo = 0;
3651 }
1c79356b 3652
2d21ac55
A
3653 /* First wait for any other process doing a flush to complete. */
3654 lck_mtx_lock(nfs_buf_mutex);
3655 while (np->n_bflag & NBINVALINPROG) {
3656 np->n_bflag |= NBINVALWANT;
3657 error = msleep(&np->n_bflag, nfs_buf_mutex, slpflag, "nfs_vinvalbuf", NULL);
55e303ae 3658 if (error) {
2d21ac55 3659 lck_mtx_unlock(nfs_buf_mutex);
55e303ae 3660 return (error);
1c79356b 3661 }
1c79356b 3662 }
2d21ac55
A
3663 np->n_bflag |= NBINVALINPROG;
3664 lck_mtx_unlock(nfs_buf_mutex);
3665
3666 /* Now, flush as required. */
3667 error = nfs_vinvalbuf_internal(np, flags, thd, cred, slpflag, 0);
3668 while (error) {
3669 FSDBG(554, np, 0, 0, error);
3670 if ((error = nfs_sigintr(VTONMP(vp), NULL, thd, 0)))
3671 goto done;
3672 error = nfs_vinvalbuf_internal(np, flags, thd, cred, 0, slptimeo);
1c79356b 3673 }
2d21ac55
A
3674
3675 /* get the pages out of vm also */
3676 if (UBCINFOEXISTS(vp) && (size = ubc_getsize(vp)))
3677 if (!(rv = ubc_sync_range(vp, 0, size, UBC_PUSHALL | UBC_SYNC | UBC_INVALIDATE)))
91447636 3678 panic("nfs_vinvalbuf(): ubc_sync_range failed!");
2d21ac55
A
3679done:
3680 lck_mtx_lock(nfs_buf_mutex);
3681 nflags = np->n_bflag;
3682 np->n_bflag &= ~(NBINVALINPROG|NBINVALWANT);
3683 lck_mtx_unlock(nfs_buf_mutex);
3684 if (nflags & NBINVALWANT)
3685 wakeup(&np->n_bflag);
91447636 3686
2d21ac55
A
3687 FSDBG_BOT(554, np, flags, intrflg, error);
3688 return (error);
1c79356b
A
3689}
3690
3691/*
2d21ac55
A
3692 * Add an async I/O request to the mount's async I/O queue and make
3693 * sure that an nfsiod will service it.
1c79356b 3694 */
2d21ac55
A
3695void
3696nfs_asyncio_finish(struct nfsreq *req)
1c79356b
A
3697{
3698 struct nfsmount *nmp;
2d21ac55
A
3699 struct nfsiod *niod;
3700 int started = 0;
1c79356b 3701
2d21ac55 3702 FSDBG_TOP(552, nmp, 0, 0, 0);
1c79356b 3703again:
2d21ac55
A
3704 if (((nmp = req->r_nmp)) == NULL)
3705 return;
3706 lck_mtx_lock(nfsiod_mutex);
3707 niod = nmp->nm_niod;
3708
3709 /* grab an nfsiod if we don't have one already */
3710 if (!niod) {
3711 niod = TAILQ_FIRST(&nfsiodfree);
3712 if (niod) {
3713 TAILQ_REMOVE(&nfsiodfree, niod, niod_link);
3714 TAILQ_INSERT_TAIL(&nfsiodwork, niod, niod_link);
3715 niod->niod_nmp = nmp;
3716 } else if (((nfsiod_thread_count < NFSIOD_MAX) || (nfsiod_thread_count <= 0)) && (started < 4)) {
1c79356b 3717 /*
2d21ac55
A
3718 * Try starting a new thread.
3719 * We may try a couple times if other callers
3720 * get the new threads before we do.
1c79356b 3721 */
2d21ac55
A
3722 lck_mtx_unlock(nfsiod_mutex);
3723 started++;
3724 if (!nfsiod_start())
3725 goto again;
3726 lck_mtx_lock(nfsiod_mutex);
1c79356b 3727 }
91447636 3728 }
55e303ae 3729
2d21ac55
A
3730 if (req->r_achain.tqe_next == NFSREQNOLIST)
3731 TAILQ_INSERT_TAIL(&nmp->nm_iodq, req, r_achain);
3732
3733 /* If this mount doesn't already have an nfsiod working on it... */
3734 if (!nmp->nm_niod) {
3735 if (niod) { /* give it the nfsiod we just grabbed */
3736 nmp->nm_niod = niod;
3737 lck_mtx_unlock(nfsiod_mutex);
3738 wakeup(niod);
3739 } else if (nfsiod_thread_count > 0) {
3740 /* just queue it up on nfsiod mounts queue */
3741 TAILQ_INSERT_TAIL(&nfsiodmounts, nmp, nm_iodlink);
3742 lck_mtx_unlock(nfsiod_mutex);
3743 } else {
3744 printf("nfs_asyncio(): no nfsiods? %d %d (%d)\n", nfsiod_thread_count, NFSIOD_MAX, started);
3745 lck_mtx_unlock(nfsiod_mutex);
3746 /* we have no other option but to be persistent */
3747 started = 0;
3748 goto again;
1c79356b 3749 }
2d21ac55
A
3750 } else {
3751 lck_mtx_unlock(nfsiod_mutex);
1c79356b
A
3752 }
3753
2d21ac55
A
3754 FSDBG_BOT(552, nmp, 0, 0, 0);
3755}
1c79356b 3756
2d21ac55
A
3757/*
3758 * queue up async I/O request for resend
3759 */
3760void
3761nfs_asyncio_resend(struct nfsreq *req)
3762{
3763 struct nfsmount *nmp = req->r_nmp;
1c79356b 3764
2d21ac55
A
3765 if (!nmp)
3766 return;
3767 nfs_gss_clnt_rpcdone(req);
3768 lck_mtx_lock(&nmp->nm_lock);
3769 if (req->r_rchain.tqe_next == NFSREQNOLIST) {
3770 TAILQ_INSERT_TAIL(&nmp->nm_resendq, req, r_rchain);
3771 req->r_flags |= R_RESENDQ;
1c79356b 3772 }
2d21ac55
A
3773 nfs_mount_sock_thread_wake(nmp);
3774 lck_mtx_unlock(&nmp->nm_lock);
1c79356b
A
3775}
3776
3777/*
2d21ac55 3778 * Read an NFS buffer for a directory.
1c79356b
A
3779 */
3780int
2d21ac55 3781nfs_buf_readdir(struct nfsbuf *bp, vfs_context_t ctx)
1c79356b 3782{
2d21ac55 3783 nfsnode_t np;
91447636 3784 vnode_t vp;
1c79356b 3785 struct nfsmount *nmp;
2d21ac55 3786 int error = 0, nfsvers;
1c79356b 3787 struct uio uio;
91447636 3788 struct iovec_32 io;
1c79356b 3789
2d21ac55
A
3790 np = bp->nb_np;
3791 vp = NFSTOV(np);
3792 nmp = VTONMP(vp);
3793 nfsvers = nmp->nm_vers;
3794 uio.uio_iovs.iov32p = &io;
3795 uio.uio_iovcnt = 1;
91447636 3796#if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
2d21ac55 3797 uio.uio_segflg = UIO_SYSSPACE;
91447636 3798#else
2d21ac55
A
3799 uio.uio_segflg = UIO_SYSSPACE32;
3800#endif
1c79356b 3801
2d21ac55
A
3802 /* sanity check */
3803 if (ISSET(bp->nb_flags, NB_DONE))
55e303ae 3804 CLR(bp->nb_flags, NB_DONE);
55e303ae 3805
2d21ac55
A
3806 uio.uio_rw = UIO_READ;
3807 io.iov_len = bp->nb_bufsize;
3808 uio_uio_resid_set(&uio, io.iov_len);
3809 io.iov_base = (uintptr_t) bp->nb_data;
3810 uio.uio_offset = NBOFF(bp);
55e303ae 3811
2d21ac55
A
3812 OSAddAtomic(1, (SInt32*)&nfsstats.readdir_bios);
3813 if (nfsvers < NFS_VER4) {
3814 if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
3815 error = nfs3_readdirplus_rpc(np, &uio, ctx);
3816 if (error == NFSERR_NOTSUPP) {
3817 lck_mtx_lock(&nmp->nm_lock);
3818 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
3819 lck_mtx_unlock(&nmp->nm_lock);
1c79356b 3820 }
fa4905b1 3821 }
2d21ac55
A
3822 if (!(nmp->nm_flag & NFSMNT_RDIRPLUS))
3823 error = nfs3_readdir_rpc(np, &uio, ctx);
3824 } else {
3825 error = nfs4_readdir_rpc(np, &uio, ctx);
3826 }
3827 if (error) {
55e303ae
A
3828 SET(bp->nb_flags, NB_ERROR);
3829 bp->nb_error = error;
2d21ac55
A
3830 } else {
3831 bp->nb_validoff = 0;
3832 bp->nb_validend = uio.uio_offset - NBOFF(bp);
3833 bp->nb_valid = (1 << (round_page_32(bp->nb_validend)/PAGE_SIZE)) - 1;
1c79356b 3834 }
1c79356b 3835
55e303ae 3836 nfs_buf_iodone(bp);
1c79356b
A
3837 return (error);
3838}