xref: /dflybsd-src/sys/vfs/hammer/hammer_io.c (revision f0a5c1029a4d9e5497fe457e38db8db7a021dc86)
1 /*
2  * Copyright (c) 2007-2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.33 2008/05/18 21:47:06 dillon Exp $
35  */
36 /*
37  * IO Primitives and buffer cache management
38  *
39  * All major data-tracking structures in HAMMER contain a struct hammer_io
40  * which is used to manage their backing store.  We use filesystem buffers
41  * for backing store and we leave them passively associated with their
42  * HAMMER structures.
43  *
44  * If the kernel tries to release a passively associated buf which we cannot
45  * yet let go we set B_LOCKED in the buffer and then actively released it
46  * later when we can.
47  */
48 
49 #include "hammer.h"
50 #include <sys/fcntl.h>
51 #include <sys/nlookup.h>
52 #include <sys/buf.h>
53 #include <sys/buf2.h>
54 
55 static void hammer_io_modify(hammer_io_t io, int count);
56 static void hammer_io_deallocate(struct buf *bp);
57 
58 /*
59  * Initialize a new, already-zero'd hammer_io structure, or reinitialize
60  * an existing hammer_io structure which may have switched to another type.
61  */
62 void
63 hammer_io_init(hammer_io_t io, hammer_mount_t hmp, enum hammer_io_type type)
64 {
65 	io->hmp = hmp;
66 	io->type = type;
67 }
68 
69 void
70 hammer_io_reinit(hammer_io_t io, enum hammer_io_type type)
71 {
72 	hammer_mount_t hmp = io->hmp;
73 
74 	if (io->modified) {
75 		KKASSERT(io->mod_list != NULL);
76 		if (io->mod_list == &hmp->volu_list ||
77 		    io->mod_list == &hmp->meta_list) {
78 			--hmp->locked_dirty_count;
79 			--hammer_count_dirtybufs;
80 		}
81 		TAILQ_REMOVE(io->mod_list, io, mod_entry);
82 		io->mod_list = NULL;
83 	}
84 	io->type = type;
85 	if (io->modified) {
86 		switch(io->type) {
87 		case HAMMER_STRUCTURE_VOLUME:
88 			io->mod_list = &hmp->volu_list;
89 			++hmp->locked_dirty_count;
90 			++hammer_count_dirtybufs;
91 			break;
92 		case HAMMER_STRUCTURE_META_BUFFER:
93 			io->mod_list = &hmp->meta_list;
94 			++hmp->locked_dirty_count;
95 			++hammer_count_dirtybufs;
96 			break;
97 		case HAMMER_STRUCTURE_UNDO_BUFFER:
98 			io->mod_list = &hmp->undo_list;
99 			break;
100 		case HAMMER_STRUCTURE_DATA_BUFFER:
101 			io->mod_list = &hmp->data_list;
102 			break;
103 		}
104 		TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry);
105 	}
106 }
107 
108 /*
109  * Helper routine to disassociate a buffer cache buffer from an I/O
110  * structure.  Called with the io structure exclusively locked.
111  *
112  * The io may have 0 or 1 references depending on who called us.  The
113  * caller is responsible for dealing with the refs.
114  *
115  * This call can only be made when no action is required on the buffer.
116  * HAMMER must own the buffer (released == 0) since we mess around with it.
117  */
118 static void
119 hammer_io_disassociate(hammer_io_structure_t iou, int elseit)
120 {
121 	struct buf *bp = iou->io.bp;
122 
123 	KKASSERT(iou->io.modified == 0);
124 	buf_dep_init(bp);
125 	iou->io.bp = NULL;
126 	bp->b_flags &= ~B_LOCKED;
127 	if (elseit) {
128 		KKASSERT(iou->io.released == 0);
129 		iou->io.released = 1;
130 		bqrelse(bp);
131 	} else {
132 		KKASSERT(iou->io.released);
133 	}
134 
135 	switch(iou->io.type) {
136 	case HAMMER_STRUCTURE_VOLUME:
137 		iou->volume.ondisk = NULL;
138 		break;
139 	case HAMMER_STRUCTURE_DATA_BUFFER:
140 	case HAMMER_STRUCTURE_META_BUFFER:
141 	case HAMMER_STRUCTURE_UNDO_BUFFER:
142 		iou->buffer.ondisk = NULL;
143 		break;
144 	}
145 }
146 
147 /*
148  * Wait for any physical IO to complete
149  */
150 static void
151 hammer_io_wait(hammer_io_t io)
152 {
153 	if (io->running) {
154 		crit_enter();
155 		tsleep_interlock(io);
156 		io->waiting = 1;
157 		for (;;) {
158 			tsleep(io, 0, "hmrflw", 0);
159 			if (io->running == 0)
160 				break;
161 			tsleep_interlock(io);
162 			io->waiting = 1;
163 			if (io->running == 0)
164 				break;
165 		}
166 		crit_exit();
167 	}
168 }
169 
170 #define HAMMER_MAXRA	4
171 
172 /*
173  * Load bp for a HAMMER structure.  The io must be exclusively locked by
174  * the caller.
175  *
176  * Generally speaking HAMMER assumes either an optimized layout or that
177  * typical access patterns will be close to the original layout when the
178  * information was written.  For this reason we try to cluster all reads.
179  */
180 int
181 hammer_io_read(struct vnode *devvp, struct hammer_io *io, hammer_off_t limit)
182 {
183 	struct buf *bp;
184 	int   error;
185 
186 	if ((bp = io->bp) == NULL) {
187 #if 1
188 		error = cluster_read(devvp, limit, io->offset,
189 				     HAMMER_BUFSIZE, MAXBSIZE, 16, &io->bp);
190 #else
191 		error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp);
192 #endif
193 
194 		if (error == 0) {
195 			bp = io->bp;
196 			bp->b_ops = &hammer_bioops;
197 			LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
198 			BUF_KERNPROC(bp);
199 		}
200 		KKASSERT(io->modified == 0);
201 		KKASSERT(io->running == 0);
202 		KKASSERT(io->waiting == 0);
203 		io->released = 0;	/* we hold an active lock on bp */
204 	} else {
205 		error = 0;
206 	}
207 	return(error);
208 }
209 
210 /*
211  * Similar to hammer_io_read() but returns a zero'd out buffer instead.
212  * Must be called with the IO exclusively locked.
213  *
214  * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background
215  * I/O by forcing the buffer to not be in a released state before calling
216  * it.
217  *
218  * This function will also mark the IO as modified but it will not
219  * increment the modify_refs count.
220  */
221 int
222 hammer_io_new(struct vnode *devvp, struct hammer_io *io)
223 {
224 	struct buf *bp;
225 
226 	if ((bp = io->bp) == NULL) {
227 		io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0);
228 		bp = io->bp;
229 		bp->b_ops = &hammer_bioops;
230 		LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
231 		io->released = 0;
232 		KKASSERT(io->running == 0);
233 		io->waiting = 0;
234 		BUF_KERNPROC(bp);
235 	} else {
236 		if (io->released) {
237 			regetblk(bp);
238 			BUF_KERNPROC(bp);
239 			io->released = 0;
240 		}
241 	}
242 	hammer_io_modify(io, 0);
243 	vfs_bio_clrbuf(bp);
244 	return(0);
245 }
246 
247 /*
248  * This routine is called on the last reference to a hammer structure.
249  * The io is usually locked exclusively (but may not be during unmount).
250  *
251  * This routine is responsible for the disposition of the buffer cache
252  * buffer backing the IO.  Only pure-data and undo buffers can be handed
253  * back to the kernel.  Volume and meta-data buffers must be retained
254  * by HAMMER until explicitly flushed by the backend.
255  */
256 void
257 hammer_io_release(struct hammer_io *io, int flush)
258 {
259 	struct buf *bp;
260 
261 	if ((bp = io->bp) == NULL)
262 		return;
263 
264 	/*
265 	 * Try to flush a dirty IO to disk if asked to by the
266 	 * caller or if the kernel tried to flush the buffer in the past.
267 	 *
268 	 * Kernel-initiated flushes are only allowed for pure-data buffers.
269 	 * meta-data and volume buffers can only be flushed explicitly
270 	 * by HAMMER.
271 	 */
272 	if (io->modified) {
273 		if (flush) {
274 			hammer_io_flush(io);
275 		} else if (bp->b_flags & B_LOCKED) {
276 			switch(io->type) {
277 			case HAMMER_STRUCTURE_DATA_BUFFER:
278 			case HAMMER_STRUCTURE_UNDO_BUFFER:
279 				hammer_io_flush(io);
280 				break;
281 			default:
282 				break;
283 			}
284 		} /* else no explicit request to flush the buffer */
285 	}
286 
287 	/*
288 	 * Wait for the IO to complete if asked to.
289 	 */
290 	if (io->waitdep && io->running) {
291 		hammer_io_wait(io);
292 	}
293 
294 	/*
295 	 * Return control of the buffer to the kernel (with the provisio
296 	 * that our bioops can override kernel decisions with regards to
297 	 * the buffer).
298 	 */
299 	if (flush && io->modified == 0 && io->running == 0) {
300 		/*
301 		 * Always disassociate the bp if an explicit flush
302 		 * was requested and the IO completed with no error
303 		 * (so unmount can really clean up the structure).
304 		 */
305 		if (io->released) {
306 			regetblk(bp);
307 			BUF_KERNPROC(bp);
308 			io->released = 0;
309 		}
310 		hammer_io_disassociate((hammer_io_structure_t)io, 1);
311 	} else if (io->modified) {
312 		/*
313 		 * Only certain IO types can be released to the kernel.
314 		 * volume and meta-data IO types must be explicitly flushed
315 		 * by HAMMER.
316 		 */
317 		switch(io->type) {
318 		case HAMMER_STRUCTURE_DATA_BUFFER:
319 		case HAMMER_STRUCTURE_UNDO_BUFFER:
320 			if (io->released == 0) {
321 				io->released = 1;
322 				bdwrite(bp);
323 			}
324 			break;
325 		default:
326 			break;
327 		}
328 	} else if (io->released == 0) {
329 		/*
330 		 * Clean buffers can be generally released to the kernel.
331 		 * We leave the bp passively associated with the HAMMER
332 		 * structure and use bioops to disconnect it later on
333 		 * if the kernel wants to discard the buffer.
334 		 */
335 		bp->b_flags &= ~B_LOCKED;
336 		io->released = 1;
337 		bqrelse(bp);
338 	} else {
339 		/*
340 		 * A released buffer may have been locked when the kernel
341 		 * tried to deallocate it while HAMMER still had references
342 		 * on the hammer_buffer.  We must unlock the buffer or
343 		 * it will just rot.
344 		 */
345 		crit_enter();
346 		if (io->running == 0 && (bp->b_flags & B_LOCKED)) {
347 			regetblk(bp);
348 			bp->b_flags &= ~B_LOCKED;
349 			bqrelse(bp);
350 		}
351 		crit_exit();
352 	}
353 }
354 
355 /*
356  * This routine is called with a locked IO when a flush is desired and
357  * no other references to the structure exists other then ours.  This
358  * routine is ONLY called when HAMMER believes it is safe to flush a
359  * potentially modified buffer out.
360  */
361 void
362 hammer_io_flush(struct hammer_io *io)
363 {
364 	struct buf *bp;
365 
366 	/*
367 	 * Degenerate case - nothing to flush if nothing is dirty.
368 	 */
369 	if (io->modified == 0) {
370 		return;
371 	}
372 
373 	KKASSERT(io->bp);
374 	KKASSERT(io->modify_refs == 0);
375 
376 	/*
377 	 * Acquire ownership of the bp, particularly before we clear our
378 	 * modified flag.
379 	 *
380 	 * We are going to bawrite() this bp.  Don't leave a window where
381 	 * io->released is set, we actually own the bp rather then our
382 	 * buffer.
383 	 */
384 	bp = io->bp;
385 	if (io->released) {
386 		regetblk(bp);
387 		/* BUF_KERNPROC(io->bp); */
388 		/* io->released = 0; */
389 		KKASSERT(io->released);
390 		KKASSERT(io->bp == bp);
391 	}
392 	io->released = 1;
393 
394 	/*
395 	 * Acquire exclusive access to the bp and then clear the modified
396 	 * state of the buffer prior to issuing I/O to interlock any
397 	 * modifications made while the I/O is in progress.  This shouldn't
398 	 * happen anyway but losing data would be worse.  The modified bit
399 	 * will be rechecked after the IO completes.
400 	 *
401 	 * This is only legal when lock.refs == 1 (otherwise we might clear
402 	 * the modified bit while there are still users of the cluster
403 	 * modifying the data).
404 	 *
405 	 * Do this before potentially blocking so any attempt to modify the
406 	 * ondisk while we are blocked blocks waiting for us.
407 	 */
408 	KKASSERT(io->mod_list != NULL);
409 	if (io->mod_list == &io->hmp->volu_list ||
410 	    io->mod_list == &io->hmp->meta_list) {
411 		--io->hmp->locked_dirty_count;
412 		--hammer_count_dirtybufs;
413 	}
414 	TAILQ_REMOVE(io->mod_list, io, mod_entry);
415 	io->mod_list = NULL;
416 	io->modified = 0;
417 
418 	/*
419 	 * Transfer ownership to the kernel and initiate I/O.
420 	 */
421 	io->running = 1;
422 	++io->hmp->io_running_count;
423 	bawrite(bp);
424 }
425 
426 /************************************************************************
427  *				BUFFER DIRTYING				*
428  ************************************************************************
429  *
430  * These routines deal with dependancies created when IO buffers get
431  * modified.  The caller must call hammer_modify_*() on a referenced
432  * HAMMER structure prior to modifying its on-disk data.
433  *
434  * Any intent to modify an IO buffer acquires the related bp and imposes
435  * various write ordering dependancies.
436  */
437 
438 /*
439  * Mark a HAMMER structure as undergoing modification.  Meta-data buffers
440  * are locked until the flusher can deal with them, pure data buffers
441  * can be written out.
442  */
443 static
444 void
445 hammer_io_modify(hammer_io_t io, int count)
446 {
447 	struct hammer_mount *hmp = io->hmp;
448 
449 	/*
450 	 * Shortcut if nothing to do.
451 	 */
452 	KKASSERT(io->lock.refs != 0 && io->bp != NULL);
453 	io->modify_refs += count;
454 	if (io->modified && io->released == 0)
455 		return;
456 
457 	hammer_lock_ex(&io->lock);
458 	if (io->modified == 0) {
459 		KKASSERT(io->mod_list == NULL);
460 		switch(io->type) {
461 		case HAMMER_STRUCTURE_VOLUME:
462 			io->mod_list = &hmp->volu_list;
463 			++hmp->locked_dirty_count;
464 			++hammer_count_dirtybufs;
465 			break;
466 		case HAMMER_STRUCTURE_META_BUFFER:
467 			io->mod_list = &hmp->meta_list;
468 			++hmp->locked_dirty_count;
469 			++hammer_count_dirtybufs;
470 			break;
471 		case HAMMER_STRUCTURE_UNDO_BUFFER:
472 			io->mod_list = &hmp->undo_list;
473 			break;
474 		case HAMMER_STRUCTURE_DATA_BUFFER:
475 			io->mod_list = &hmp->data_list;
476 			break;
477 		}
478 		TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry);
479 		io->modified = 1;
480 	}
481 	if (io->released) {
482 		regetblk(io->bp);
483 		BUF_KERNPROC(io->bp);
484 		io->released = 0;
485 		KKASSERT(io->modified != 0);
486 	}
487 	hammer_unlock(&io->lock);
488 }
489 
490 static __inline
491 void
492 hammer_io_modify_done(hammer_io_t io)
493 {
494 	KKASSERT(io->modify_refs > 0);
495 	--io->modify_refs;
496 }
497 
498 /*
499  * Caller intends to modify a volume's ondisk structure.
500  *
501  * This is only allowed if we are the flusher or we have a ref on the
502  * sync_lock.
503  */
504 void
505 hammer_modify_volume(hammer_transaction_t trans, hammer_volume_t volume,
506 		     void *base, int len)
507 {
508 	KKASSERT (trans == NULL || trans->sync_lock_refs > 0);
509 
510 	hammer_io_modify(&volume->io, 1);
511 	if (len) {
512 		intptr_t rel_offset = (intptr_t)base - (intptr_t)volume->ondisk;
513 		KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
514 		hammer_generate_undo(trans, &volume->io,
515 			 HAMMER_ENCODE_RAW_VOLUME(volume->vol_no, rel_offset),
516 			 base, len);
517 	}
518 }
519 
520 /*
521  * Caller intends to modify a buffer's ondisk structure.
522  *
523  * This is only allowed if we are the flusher or we have a ref on the
524  * sync_lock.
525  */
526 void
527 hammer_modify_buffer(hammer_transaction_t trans, hammer_buffer_t buffer,
528 		     void *base, int len)
529 {
530 	KKASSERT (trans == NULL || trans->sync_lock_refs > 0);
531 
532 	hammer_io_modify(&buffer->io, 1);
533 	if (len) {
534 		intptr_t rel_offset = (intptr_t)base - (intptr_t)buffer->ondisk;
535 		KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
536 		hammer_generate_undo(trans, &buffer->io,
537 				     buffer->zone2_offset + rel_offset,
538 				     base, len);
539 	}
540 }
541 
542 void
543 hammer_modify_volume_done(hammer_volume_t volume)
544 {
545 	hammer_io_modify_done(&volume->io);
546 }
547 
548 void
549 hammer_modify_buffer_done(hammer_buffer_t buffer)
550 {
551 	hammer_io_modify_done(&buffer->io);
552 }
553 
554 /*
555  * Mark an entity as not being dirty any more -- this usually occurs when
556  * the governing a-list has freed the entire entity.
557  *
558  * XXX
559  */
560 void
561 hammer_io_clear_modify(struct hammer_io *io)
562 {
563 #if 0
564 	struct buf *bp;
565 
566 	io->modified = 0;
567 	XXX mod_list/entry
568 	if ((bp = io->bp) != NULL) {
569 		if (io->released) {
570 			regetblk(bp);
571 			/* BUF_KERNPROC(io->bp); */
572 		} else {
573 			io->released = 1;
574 		}
575 		if (io->modified == 0) {
576 			hkprintf("hammer_io_clear_modify: cleared %p\n", io);
577 			bundirty(bp);
578 			bqrelse(bp);
579 		} else {
580 			bdwrite(bp);
581 		}
582 	}
583 #endif
584 }
585 
586 /************************************************************************
587  *				HAMMER_BIOOPS				*
588  ************************************************************************
589  *
590  */
591 
592 /*
593  * Pre-IO initiation kernel callback - cluster build only
594  */
595 static void
596 hammer_io_start(struct buf *bp)
597 {
598 }
599 
600 /*
601  * Post-IO completion kernel callback
602  *
603  * NOTE: HAMMER may modify a buffer after initiating I/O.  The modified bit
604  * may also be set if we were marking a cluster header open.  Only remove
605  * our dependancy if the modified bit is clear.
606  */
607 static void
608 hammer_io_complete(struct buf *bp)
609 {
610 	union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
611 
612 	KKASSERT(iou->io.released == 1);
613 
614 	if (iou->io.running) {
615 		if (--iou->io.hmp->io_running_count == 0)
616 			wakeup(&iou->io.hmp->io_running_count);
617 		KKASSERT(iou->io.hmp->io_running_count >= 0);
618 		iou->io.running = 0;
619 	}
620 
621 	/*
622 	 * If no lock references remain and we can acquire the IO lock and
623 	 * someone at some point wanted us to flush (B_LOCKED test), then
624 	 * try to dispose of the IO.
625 	 */
626 	if (iou->io.waiting) {
627 		iou->io.waiting = 0;
628 		wakeup(iou);
629 	}
630 
631 	/*
632 	 * Someone wanted us to flush, try to clean out the buffer.
633 	 */
634 	if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) {
635 		KKASSERT(iou->io.modified == 0);
636 		bp->b_flags &= ~B_LOCKED;
637 		hammer_io_deallocate(bp);
638 		/* structure may be dead now */
639 	}
640 }
641 
642 /*
643  * Callback from kernel when it wishes to deallocate a passively
644  * associated structure.  This mostly occurs with clean buffers
645  * but it may be possible for a holding structure to be marked dirty
646  * while its buffer is passively associated.
647  *
648  * If we cannot disassociate we set B_LOCKED to prevent the buffer
649  * from getting reused.
650  *
651  * WARNING: Because this can be called directly by getnewbuf we cannot
652  * recurse into the tree.  If a bp cannot be immediately disassociated
653  * our only recourse is to set B_LOCKED.
654  */
655 static void
656 hammer_io_deallocate(struct buf *bp)
657 {
658 	hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep);
659 
660 	KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0);
661 	if (iou->io.lock.refs > 0 || iou->io.modified) {
662 		/*
663 		 * It is not legal to disassociate a modified buffer.  This
664 		 * case really shouldn't ever occur.
665 		 */
666 		bp->b_flags |= B_LOCKED;
667 	} else {
668 		/*
669 		 * Disassociate the BP.  If the io has no refs left we
670 		 * have to add it to the loose list.
671 		 */
672 		hammer_io_disassociate(iou, 0);
673 		if (iou->io.bp == NULL &&
674 		    iou->io.type != HAMMER_STRUCTURE_VOLUME) {
675 			KKASSERT(iou->io.mod_list == NULL);
676 			iou->io.mod_list = &iou->io.hmp->lose_list;
677 			TAILQ_INSERT_TAIL(iou->io.mod_list, &iou->io, mod_entry);
678 		}
679 	}
680 }
681 
682 static int
683 hammer_io_fsync(struct vnode *vp)
684 {
685 	return(0);
686 }
687 
688 /*
689  * NOTE: will not be called unless we tell the kernel about the
690  * bioops.  Unused... we use the mount's VFS_SYNC instead.
691  */
692 static int
693 hammer_io_sync(struct mount *mp)
694 {
695 	return(0);
696 }
697 
698 static void
699 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
700 {
701 }
702 
703 /*
704  * I/O pre-check for reading and writing.  HAMMER only uses this for
705  * B_CACHE buffers so checkread just shouldn't happen, but if it does
706  * allow it.
707  *
708  * Writing is a different case.  We don't want the kernel to try to write
709  * out a buffer that HAMMER may be modifying passively or which has a
710  * dependancy.  In addition, kernel-demanded writes can only proceed for
711  * certain types of buffers (i.e. UNDO and DATA types).  Other dirty
712  * buffer types can only be explicitly written by the flusher.
713  *
714  * checkwrite will only be called for bdwrite()n buffers.  If we return
715  * success the kernel is guaranteed to initiate the buffer write.
716  */
717 static int
718 hammer_io_checkread(struct buf *bp)
719 {
720 	return(0);
721 }
722 
723 static int
724 hammer_io_checkwrite(struct buf *bp)
725 {
726 	hammer_io_t io = (void *)LIST_FIRST(&bp->b_dep);
727 
728 	/*
729 	 * This shouldn't happen under normal operation.
730 	 */
731 	if (io->type == HAMMER_STRUCTURE_VOLUME ||
732 	    io->type == HAMMER_STRUCTURE_META_BUFFER) {
733 		if (!panicstr)
734 			panic("hammer_io_checkwrite: illegal buffer");
735 		hkprintf("x");
736 		bp->b_flags |= B_LOCKED;
737 		return(1);
738 	}
739 
740 	/*
741 	 * We can only clear the modified bit if the IO is not currently
742 	 * undergoing modification.  Otherwise we may miss changes.
743 	 */
744 	if (io->modify_refs == 0 && io->modified) {
745 		KKASSERT(io->mod_list != NULL);
746 		if (io->mod_list == &io->hmp->volu_list ||
747 		    io->mod_list == &io->hmp->meta_list) {
748 			--io->hmp->locked_dirty_count;
749 			--hammer_count_dirtybufs;
750 		}
751 		TAILQ_REMOVE(io->mod_list, io, mod_entry);
752 		io->mod_list = NULL;
753 		io->modified = 0;
754 	}
755 
756 	/*
757 	 * The kernel is going to start the IO, set io->running.
758 	 */
759 	KKASSERT(io->running == 0);
760 	io->running = 1;
761 	++io->hmp->io_running_count;
762 	return(0);
763 }
764 
765 /*
766  * Return non-zero if we wish to delay the kernel's attempt to flush
767  * this buffer to disk.
768  */
769 static int
770 hammer_io_countdeps(struct buf *bp, int n)
771 {
772 	return(0);
773 }
774 
775 struct bio_ops hammer_bioops = {
776 	.io_start	= hammer_io_start,
777 	.io_complete	= hammer_io_complete,
778 	.io_deallocate	= hammer_io_deallocate,
779 	.io_fsync	= hammer_io_fsync,
780 	.io_sync	= hammer_io_sync,
781 	.io_movedeps	= hammer_io_movedeps,
782 	.io_countdeps	= hammer_io_countdeps,
783 	.io_checkread	= hammer_io_checkread,
784 	.io_checkwrite	= hammer_io_checkwrite,
785 };
786 
787