12e64daa1e727508721abe2a5e1b4fef9f176f46
[dragonfly.git] / sys / vfs / hammer / hammer_io.c
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.28 2008/04/27 00:45:37 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 /*
171  * Load bp for a HAMMER structure.  The io must be exclusively locked by
172  * the caller.
173  */
174 int
175 hammer_io_read(struct vnode *devvp, struct hammer_io *io)
176 {
177         struct buf *bp;
178         int error;
179
180         if ((bp = io->bp) == NULL) {
181                 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp);
182                 if (error == 0) {
183                         bp = io->bp;
184                         bp->b_ops = &hammer_bioops;
185                         LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
186                         BUF_KERNPROC(bp);
187                 }
188                 KKASSERT(io->modified == 0);
189                 KKASSERT(io->running == 0);
190                 KKASSERT(io->waiting == 0);
191                 io->released = 0;       /* we hold an active lock on bp */
192         } else {
193                 error = 0;
194         }
195         return(error);
196 }
197
198 /*
199  * Similar to hammer_io_read() but returns a zero'd out buffer instead.
200  * Must be called with the IO exclusively locked.
201  *
202  * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background
203  * I/O by forcing the buffer to not be in a released state before calling
204  * it.
205  *
206  * This function will also mark the IO as modified but it will not
207  * increment the modify_refs count.
208  */
209 int
210 hammer_io_new(struct vnode *devvp, struct hammer_io *io)
211 {
212         struct buf *bp;
213
214         if ((bp = io->bp) == NULL) {
215                 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0);
216                 bp = io->bp;
217                 bp->b_ops = &hammer_bioops;
218                 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
219                 io->released = 0;
220                 KKASSERT(io->running == 0);
221                 io->waiting = 0;
222                 BUF_KERNPROC(bp);
223         } else {
224                 if (io->released) {
225                         regetblk(bp);
226                         BUF_KERNPROC(bp);
227                         io->released = 0;
228                 }
229         }
230         hammer_io_modify(io, 0);
231         vfs_bio_clrbuf(bp);
232         return(0);
233 }
234
235 /*
236  * This routine is called on the last reference to a hammer structure.
237  * The io is usually locked exclusively (but may not be during unmount).
238  *
239  * This routine is responsible for the disposition of the buffer cache
240  * buffer backing the IO.  Only pure-data and undo buffers can be handed
241  * back to the kernel.  Volume and meta-data buffers must be retained
242  * by HAMMER until explicitly flushed by the backend.
243  */
244 void
245 hammer_io_release(struct hammer_io *io)
246 {
247         struct buf *bp;
248
249         if ((bp = io->bp) == NULL)
250                 return;
251
252         /*
253          * Try to flush a dirty IO to disk if asked to by the
254          * caller or if the kernel tried to flush the buffer in the past.
255          *
256          * Kernel-initiated flushes are only allowed for pure-data buffers.
257          * meta-data and volume buffers can only be flushed explicitly
258          * by HAMMER.
259          */
260         if (io->modified) {
261                 if (io->flush) {
262                         hammer_io_flush(io);
263                 } else if (bp->b_flags & B_LOCKED) {
264                         switch(io->type) {
265                         case HAMMER_STRUCTURE_DATA_BUFFER:
266                         case HAMMER_STRUCTURE_UNDO_BUFFER:
267                                 hammer_io_flush(io);
268                                 break;
269                         default:
270                                 break;
271                         }
272                 } /* else no explicit request to flush the buffer */
273         }
274
275         /*
276          * Wait for the IO to complete if asked to.
277          */
278         if (io->waitdep && io->running) {
279                 hammer_io_wait(io);
280         }
281
282         /*
283          * Return control of the buffer to the kernel (with the provisio
284          * that our bioops can override kernel decisions with regards to
285          * the buffer).
286          */
287         if (io->flush && io->modified == 0 && io->running == 0) {
288                 /*
289                  * Always disassociate the bp if an explicit flush
290                  * was requested and the IO completed with no error
291                  * (so unmount can really clean up the structure).
292                  */
293                 if (io->released) {
294                         regetblk(bp);
295                         BUF_KERNPROC(bp);
296                         io->released = 0;
297                 }
298                 hammer_io_disassociate((hammer_io_structure_t)io, 1);
299         } else if (io->modified) {
300                 /*
301                  * Only certain IO types can be released to the kernel.
302                  * volume and meta-data IO types must be explicitly flushed
303                  * by HAMMER.
304                  */
305                 switch(io->type) {
306                 case HAMMER_STRUCTURE_DATA_BUFFER:
307                 case HAMMER_STRUCTURE_UNDO_BUFFER:
308                         if (io->released == 0) {
309                                 io->released = 1;
310                                 bdwrite(bp);
311                         }
312                         break;
313                 default:
314                         break;
315                 }
316         } else if (io->released == 0) {
317                 /*
318                  * Clean buffers can be generally released to the kernel.
319                  * We leave the bp passively associated with the HAMMER
320                  * structure and use bioops to disconnect it later on
321                  * if the kernel wants to discard the buffer.
322                  */
323                 io->released = 1;
324                 bqrelse(bp);
325         }
326 }
327
328 /*
329  * This routine is called with a locked IO when a flush is desired and
330  * no other references to the structure exists other then ours.  This
331  * routine is ONLY called when HAMMER believes it is safe to flush a
332  * potentially modified buffer out.
333  */
334 void
335 hammer_io_flush(struct hammer_io *io)
336 {
337         struct buf *bp;
338
339         /*
340          * Degenerate case - nothing to flush if nothing is dirty.
341          */
342         if (io->modified == 0) {
343                 io->flush = 0;
344                 return;
345         }
346
347         KKASSERT(io->bp);
348         KKASSERT(io->modify_refs == 0);
349
350         /*
351          * Acquire exclusive access to the bp and then clear the modified
352          * state of the buffer prior to issuing I/O to interlock any
353          * modifications made while the I/O is in progress.  This shouldn't
354          * happen anyway but losing data would be worse.  The modified bit
355          * will be rechecked after the IO completes.
356          *
357          * This is only legal when lock.refs == 1 (otherwise we might clear
358          * the modified bit while there are still users of the cluster
359          * modifying the data).
360          *
361          * Do this before potentially blocking so any attempt to modify the
362          * ondisk while we are blocked blocks waiting for us.
363          */
364         KKASSERT(io->mod_list != NULL);
365         if (io->mod_list == &io->hmp->volu_list ||
366             io->mod_list == &io->hmp->meta_list) {
367                 --io->hmp->locked_dirty_count;
368                 --hammer_count_dirtybufs;
369         }
370         TAILQ_REMOVE(io->mod_list, io, mod_entry);
371         io->mod_list = NULL;
372         io->modified = 0;
373         io->flush = 0;
374         bp = io->bp;
375
376         /*
377          * Acquire ownership (released variable set for clarity)
378          */
379         if (io->released) {
380                 regetblk(bp);
381                 /* BUF_KERNPROC(io->bp); */
382                 io->released = 0;
383         }
384
385         /*
386          * Transfer ownership to the kernel and initiate I/O.
387          */
388         io->released = 1;
389         io->running = 1;
390         ++io->hmp->io_running_count;
391         bawrite(bp);
392 }
393
394 /************************************************************************
395  *                              BUFFER DIRTYING                         *
396  ************************************************************************
397  *
398  * These routines deal with dependancies created when IO buffers get
399  * modified.  The caller must call hammer_modify_*() on a referenced
400  * HAMMER structure prior to modifying its on-disk data.
401  *
402  * Any intent to modify an IO buffer acquires the related bp and imposes
403  * various write ordering dependancies.
404  */
405
406 /*
407  * Mark a HAMMER structure as undergoing modification.  Meta-data buffers
408  * are locked until the flusher can deal with them, pure data buffers
409  * can be written out.
410  */
411 static
412 void
413 hammer_io_modify(hammer_io_t io, int count)
414 {
415         struct hammer_mount *hmp = io->hmp;
416
417         /*
418          * Shortcut if nothing to do.
419          */
420         KKASSERT(io->lock.refs != 0 && io->bp != NULL);
421         io->modify_refs += count;
422         if (io->modified && io->released == 0)
423                 return;
424
425         hammer_lock_ex(&io->lock);
426         if (io->modified == 0) {
427                 KKASSERT(io->mod_list == NULL);
428                 switch(io->type) {
429                 case HAMMER_STRUCTURE_VOLUME:
430                         io->mod_list = &hmp->volu_list;
431                         ++hmp->locked_dirty_count;
432                         ++hammer_count_dirtybufs;
433                         break;
434                 case HAMMER_STRUCTURE_META_BUFFER:
435                         io->mod_list = &hmp->meta_list;
436                         ++hmp->locked_dirty_count;
437                         ++hammer_count_dirtybufs;
438                         break;
439                 case HAMMER_STRUCTURE_UNDO_BUFFER:
440                         io->mod_list = &hmp->undo_list;
441                         break;
442                 case HAMMER_STRUCTURE_DATA_BUFFER:
443                         io->mod_list = &hmp->data_list;
444                         break;
445                 }
446                 TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry);
447                 io->modified = 1;
448         }
449         if (io->released) {
450                 regetblk(io->bp);
451                 BUF_KERNPROC(io->bp);
452                 io->released = 0;
453                 KKASSERT(io->modified != 0);
454         }
455         hammer_unlock(&io->lock);
456 }
457
458 static __inline
459 void
460 hammer_io_modify_done(hammer_io_t io)
461 {
462         KKASSERT(io->modify_refs > 0);
463         --io->modify_refs;
464 }
465
466 void
467 hammer_modify_volume(hammer_transaction_t trans, hammer_volume_t volume,
468                      void *base, int len)
469 {
470         hammer_io_modify(&volume->io, 1);
471
472         if (len) {
473                 intptr_t rel_offset = (intptr_t)base - (intptr_t)volume->ondisk;
474                 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
475                 hammer_generate_undo(trans, &volume->io,
476                          HAMMER_ENCODE_RAW_VOLUME(volume->vol_no, rel_offset),
477                          base, len);
478         }
479 }
480
481 /*
482  * Caller intends to modify a buffer's ondisk structure.  The related
483  * cluster must be marked open prior to being able to flush the modified
484  * buffer so get that I/O going now.
485  */
486 void
487 hammer_modify_buffer(hammer_transaction_t trans, hammer_buffer_t buffer,
488                      void *base, int len)
489 {
490         hammer_io_modify(&buffer->io, 1);
491         if (len) {
492                 intptr_t rel_offset = (intptr_t)base - (intptr_t)buffer->ondisk;
493                 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
494                 hammer_generate_undo(trans, &buffer->io,
495                                      buffer->zone2_offset + rel_offset,
496                                      base, len);
497         }
498 }
499
500 void
501 hammer_modify_volume_done(hammer_volume_t volume)
502 {
503         hammer_io_modify_done(&volume->io);
504 }
505
506 void
507 hammer_modify_buffer_done(hammer_buffer_t buffer)
508 {
509         hammer_io_modify_done(&buffer->io);
510 }
511
512 /*
513  * Mark an entity as not being dirty any more -- this usually occurs when
514  * the governing a-list has freed the entire entity.
515  *
516  * XXX
517  */
518 void
519 hammer_io_clear_modify(struct hammer_io *io)
520 {
521 #if 0
522         struct buf *bp;
523
524         io->modified = 0;
525         XXX mod_list/entry
526         if ((bp = io->bp) != NULL) {
527                 if (io->released) {
528                         regetblk(bp);
529                         /* BUF_KERNPROC(io->bp); */
530                 } else {
531                         io->released = 1;
532                 }
533                 if (io->modified == 0) {
534                         kprintf("hammer_io_clear_modify: cleared %p\n", io);
535                         bundirty(bp);
536                         bqrelse(bp);
537                 } else {
538                         bdwrite(bp);
539                 }
540         }
541 #endif
542 }
543
544 /************************************************************************
545  *                              HAMMER_BIOOPS                           *
546  ************************************************************************
547  *
548  */
549
550 /*
551  * Pre-IO initiation kernel callback - cluster build only
552  */
553 static void
554 hammer_io_start(struct buf *bp)
555 {
556 }
557
558 /*
559  * Post-IO completion kernel callback
560  *
561  * NOTE: HAMMER may modify a buffer after initiating I/O.  The modified bit
562  * may also be set if we were marking a cluster header open.  Only remove
563  * our dependancy if the modified bit is clear.
564  */
565 static void
566 hammer_io_complete(struct buf *bp)
567 {
568         union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
569
570         KKASSERT(iou->io.released == 1);
571
572         if (iou->io.running) {
573                 if (--iou->io.hmp->io_running_count == 0)
574                         wakeup(&iou->io.hmp->io_running_count);
575                 KKASSERT(iou->io.hmp->io_running_count >= 0);
576                 iou->io.running = 0;
577         }
578
579         /*
580          * If no lock references remain and we can acquire the IO lock and
581          * someone at some point wanted us to flush (B_LOCKED test), then
582          * try to dispose of the IO.
583          */
584         if (iou->io.waiting) {
585                 iou->io.waiting = 0;
586                 wakeup(iou);
587         }
588
589         /*
590          * Someone wanted us to flush, try to clean out the buffer. 
591          */
592         if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) {
593                 KKASSERT(iou->io.modified == 0);
594                 bp->b_flags &= ~B_LOCKED;
595                 hammer_io_deallocate(bp);
596                 /* structure may be dead now */
597         }
598 }
599
600 /*
601  * Callback from kernel when it wishes to deallocate a passively
602  * associated structure.  This mostly occurs with clean buffers
603  * but it may be possible for a holding structure to be marked dirty
604  * while its buffer is passively associated.
605  *
606  * If we cannot disassociate we set B_LOCKED to prevent the buffer
607  * from getting reused.
608  *
609  * WARNING: Because this can be called directly by getnewbuf we cannot
610  * recurse into the tree.  If a bp cannot be immediately disassociated
611  * our only recourse is to set B_LOCKED.
612  */
613 static void
614 hammer_io_deallocate(struct buf *bp)
615 {
616         hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep);
617
618         KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0);
619         if (iou->io.lock.refs > 0 || iou->io.modified) {
620                 /*
621                  * It is not legal to disassociate a modified buffer.  This
622                  * case really shouldn't ever occur.
623                  */
624                 bp->b_flags |= B_LOCKED;
625         } else {
626                 /*
627                  * Disassociate the BP.  If the io has no refs left we
628                  * have to add it to the loose list.
629                  */
630                 hammer_io_disassociate(iou, 0);
631                 if (iou->io.bp == NULL && 
632                     iou->io.type != HAMMER_STRUCTURE_VOLUME) {
633                         KKASSERT(iou->io.mod_list == NULL);
634                         iou->io.mod_list = &iou->io.hmp->lose_list;
635                         TAILQ_INSERT_TAIL(iou->io.mod_list, &iou->io, mod_entry);
636                 }
637         }
638 }
639
640 static int
641 hammer_io_fsync(struct vnode *vp)
642 {
643         return(0);
644 }
645
646 /*
647  * NOTE: will not be called unless we tell the kernel about the
648  * bioops.  Unused... we use the mount's VFS_SYNC instead.
649  */
650 static int
651 hammer_io_sync(struct mount *mp)
652 {
653         return(0);
654 }
655
656 static void
657 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
658 {
659 }
660
661 /*
662  * I/O pre-check for reading and writing.  HAMMER only uses this for
663  * B_CACHE buffers so checkread just shouldn't happen, but if it does
664  * allow it.
665  *
666  * Writing is a different case.  We don't want the kernel to try to write
667  * out a buffer that HAMMER may be modifying passively or which has a
668  * dependancy.  In addition, kernel-demanded writes can only proceed for
669  * certain types of buffers (i.e. UNDO and DATA types).  Other dirty
670  * buffer types can only be explicitly written by the flusher.
671  *
672  * checkwrite will only be called for bdwrite()n buffers.  If we return
673  * success the kernel is guaranteed to initiate the buffer write.
674  */
675 static int
676 hammer_io_checkread(struct buf *bp)
677 {
678         return(0);
679 }
680
681 static int
682 hammer_io_checkwrite(struct buf *bp)
683 {
684         hammer_io_t io = (void *)LIST_FIRST(&bp->b_dep);
685
686         /*
687          * We can only clear the modified bit if the IO is not currently
688          * undergoing modification.  Otherwise we may miss changes.
689          */
690         if (io->modify_refs == 0 && io->modified) {
691                 KKASSERT(io->mod_list != NULL);
692                 if (io->mod_list == &io->hmp->volu_list ||
693                     io->mod_list == &io->hmp->meta_list) {
694                         --io->hmp->locked_dirty_count;
695                         --hammer_count_dirtybufs;
696                 }
697                 TAILQ_REMOVE(io->mod_list, io, mod_entry);
698                 io->mod_list = NULL;
699                 io->modified = 0;
700         }
701
702         /*
703          * The kernel is going to start the IO, set io->running.
704          */
705         KKASSERT(io->running == 0);
706         io->running = 1;
707         ++io->hmp->io_running_count;
708         return(0);
709 }
710
711 /*
712  * Return non-zero if the caller should flush the structure associated
713  * with this io sub-structure.
714  */
715 int
716 hammer_io_checkflush(struct hammer_io *io)
717 {
718         if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) {
719                 return(1);
720         }
721         return(0);
722 }
723
724 /*
725  * Return non-zero if we wish to delay the kernel's attempt to flush
726  * this buffer to disk.
727  */
728 static int
729 hammer_io_countdeps(struct buf *bp, int n)
730 {
731         return(0);
732 }
733
734 struct bio_ops hammer_bioops = {
735         .io_start       = hammer_io_start,
736         .io_complete    = hammer_io_complete,
737         .io_deallocate  = hammer_io_deallocate,
738         .io_fsync       = hammer_io_fsync,
739         .io_sync        = hammer_io_sync,
740         .io_movedeps    = hammer_io_movedeps,
741         .io_countdeps   = hammer_io_countdeps,
742         .io_checkread   = hammer_io_checkread,
743         .io_checkwrite  = hammer_io_checkwrite,
744 };
745