HAMMER 53H/Many: Performance tuning, bug fixes
[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.38 2008/06/10 22:30:21 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 destroy 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 /*
70  * Helper routine to disassociate a buffer cache buffer from an I/O
71  * structure.  Called with the io structure exclusively locked.
72  *
73  * The io may have 0 or 1 references depending on who called us.  The
74  * caller is responsible for dealing with the refs.
75  *
76  * This call can only be made when no action is required on the buffer.
77  * HAMMER must own the buffer (released == 0) since we mess around with it.
78  */
79 static void
80 hammer_io_disassociate(hammer_io_structure_t iou, int elseit)
81 {
82         struct buf *bp = iou->io.bp;
83
84         KKASSERT(iou->io.modified == 0);
85         KKASSERT(LIST_FIRST(&bp->b_dep) == (void *)iou);
86         buf_dep_init(bp);
87         iou->io.bp = NULL;
88
89         /*
90          * If the buffer was locked someone wanted to get rid of it.
91          */
92         if (bp->b_flags & B_LOCKED)
93                 bp->b_flags &= ~B_LOCKED;
94
95         /*
96          * elseit is 0 when called from the kernel path, the caller is
97          * holding the buffer locked and will deal with its final disposition.
98          */
99         if (elseit) {
100                 KKASSERT(iou->io.released == 0);
101                 iou->io.released = 1;
102                 if (iou->io.reclaim)
103                         bp->b_flags |= B_NOCACHE|B_RELBUF;
104                 bqrelse(bp);
105         } else {
106                 KKASSERT(iou->io.released);
107         }
108         iou->io.reclaim = 0;
109
110         switch(iou->io.type) {
111         case HAMMER_STRUCTURE_VOLUME:
112                 iou->volume.ondisk = NULL;
113                 break;
114         case HAMMER_STRUCTURE_DATA_BUFFER:
115         case HAMMER_STRUCTURE_META_BUFFER:
116         case HAMMER_STRUCTURE_UNDO_BUFFER:
117                 iou->buffer.ondisk = NULL;
118                 break;
119         }
120 }
121
122 /*
123  * Wait for any physical IO to complete
124  */
125 static void
126 hammer_io_wait(hammer_io_t io)
127 {
128         if (io->running) {
129                 crit_enter();
130                 tsleep_interlock(io);
131                 io->waiting = 1;
132                 for (;;) {
133                         tsleep(io, 0, "hmrflw", 0);
134                         if (io->running == 0)
135                                 break;
136                         tsleep_interlock(io);
137                         io->waiting = 1;
138                         if (io->running == 0)
139                                 break;
140                 }
141                 crit_exit();
142         }
143 }
144
145 /*
146  * Wait for all hammer_io-initated write I/O's to complete.  This is not
147  * supposed to count direct I/O's but some can leak through (for
148  * non-full-sized direct I/Os).
149  */
150 void
151 hammer_io_wait_all(hammer_mount_t hmp, const char *ident)
152 {
153         crit_enter();
154         while (hmp->io_running_count)
155                 tsleep(&hmp->io_running_count, 0, ident, 0);
156         crit_exit();
157 }
158
159 #define HAMMER_MAXRA    4
160
161 /*
162  * Load bp for a HAMMER structure.  The io must be exclusively locked by
163  * the caller.
164  *
165  * Generally speaking HAMMER assumes that data is laid out fairly linearly
166  * and will cluster reads.  Conversely meta-data buffers (aka B-Tree nodes)
167  * may be dispersed due to the way the B-Tree insertion mechanism works and
168  * we only do single-buffer reads to avoid blowing out the buffer cache.
169  *
170  * Note that clustering occurs at the device layer, not the logical layer.
171  * If the buffers do not apply to the current operation they may apply to
172  * some other.
173  */
174 int
175 hammer_io_read(struct vnode *devvp, struct hammer_io *io, hammer_off_t limit)
176 {
177         struct buf *bp;
178         int   error;
179
180         if ((bp = io->bp) == NULL) {
181                 switch(io->type) {
182                 case HAMMER_STRUCTURE_DATA_BUFFER:
183                         error = cluster_read(devvp, limit, io->offset,
184                                              HAMMER_BUFSIZE,
185                                              HAMMER_CLUSTER_SIZE,
186                                              HAMMER_CLUSTER_BUFS, &io->bp);
187                         break;
188                 default:
189                         error = bread(devvp, io->offset, HAMMER_BUFSIZE,
190                                       &io->bp);
191                         break;
192                 }
193                 if (error == 0) {
194                         bp = io->bp;
195                         bp->b_ops = &hammer_bioops;
196                         KKASSERT(LIST_FIRST(&bp->b_dep) == NULL);
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                 KKASSERT(LIST_FIRST(&bp->b_dep) == NULL);
231                 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
232                 io->released = 0;
233                 KKASSERT(io->running == 0);
234                 io->waiting = 0;
235                 BUF_KERNPROC(bp);
236         } else {
237                 if (io->released) {
238                         regetblk(bp);
239                         BUF_KERNPROC(bp);
240                         io->released = 0;
241                 }
242         }
243         hammer_io_modify(io, 0);
244         vfs_bio_clrbuf(bp);
245         return(0);
246 }
247
248 /*
249  * Remove potential device level aliases against buffers managed by high level
250  * vnodes.
251  */
252 void
253 hammer_io_inval(hammer_volume_t volume, hammer_off_t zone2_offset)
254 {
255         hammer_io_structure_t iou;
256         hammer_off_t phys_offset;
257         struct buf *bp;
258
259         phys_offset = volume->ondisk->vol_buf_beg +
260                       (zone2_offset & HAMMER_OFF_SHORT_MASK);
261         if (findblk(volume->devvp, phys_offset)) {
262                 bp = getblk(volume->devvp, phys_offset, HAMMER_BUFSIZE, 0, 0);
263                 if ((iou = (void *)LIST_FIRST(&bp->b_dep)) != NULL) {
264                         hammer_io_clear_modify(&iou->io);
265                         bundirty(bp);
266                         iou->io.reclaim = 1;
267                         hammer_io_deallocate(bp);
268                 } else {
269                         KKASSERT((bp->b_flags & B_LOCKED) == 0);
270                         bundirty(bp);
271                         bp->b_flags |= B_NOCACHE|B_RELBUF;
272                         brelse(bp);
273                 }
274         }
275 }
276
277 /*
278  * This routine is called on the last reference to a hammer structure.
279  * The io is usually locked exclusively (but may not be during unmount).
280  *
281  * This routine is responsible for the disposition of the buffer cache
282  * buffer backing the IO.  Only pure-data and undo buffers can be handed
283  * back to the kernel.  Volume and meta-data buffers must be retained
284  * by HAMMER until explicitly flushed by the backend.
285  */
286 void
287 hammer_io_release(struct hammer_io *io, int flush)
288 {
289         union hammer_io_structure *iou = (void *)io;
290         struct buf *bp;
291
292         if ((bp = io->bp) == NULL)
293                 return;
294
295         /*
296          * Try to flush a dirty IO to disk if asked to by the
297          * caller or if the kernel tried to flush the buffer in the past.
298          *
299          * Kernel-initiated flushes are only allowed for pure-data buffers.
300          * meta-data and volume buffers can only be flushed explicitly
301          * by HAMMER.
302          */
303         if (io->modified) {
304                 if (flush) {
305                         hammer_io_flush(io);
306                 } else if (bp->b_flags & B_LOCKED) {
307                         switch(io->type) {
308                         case HAMMER_STRUCTURE_DATA_BUFFER:
309                         case HAMMER_STRUCTURE_UNDO_BUFFER:
310                                 hammer_io_flush(io);
311                                 break;
312                         default:
313                                 break;
314                         }
315                 } /* else no explicit request to flush the buffer */
316         }
317
318         /*
319          * Wait for the IO to complete if asked to.
320          */
321         if (io->waitdep && io->running) {
322                 hammer_io_wait(io);
323         }
324
325         /*
326          * Return control of the buffer to the kernel (with the provisio
327          * that our bioops can override kernel decisions with regards to
328          * the buffer).
329          */
330         if ((flush || io->reclaim) && io->modified == 0 && io->running == 0) {
331                 /*
332                  * Always disassociate the bp if an explicit flush
333                  * was requested and the IO completed with no error
334                  * (so unmount can really clean up the structure).
335                  */
336                 if (io->released) {
337                         regetblk(bp);
338                         BUF_KERNPROC(bp);
339                         io->released = 0;
340                 }
341                 hammer_io_disassociate((hammer_io_structure_t)io, 1);
342         } else if (io->modified) {
343                 /*
344                  * Only certain IO types can be released to the kernel.
345                  * volume and meta-data IO types must be explicitly flushed
346                  * by HAMMER.
347                  */
348                 switch(io->type) {
349                 case HAMMER_STRUCTURE_DATA_BUFFER:
350                 case HAMMER_STRUCTURE_UNDO_BUFFER:
351                         if (io->released == 0) {
352                                 io->released = 1;
353                                 bdwrite(bp);
354                         }
355                         break;
356                 default:
357                         break;
358                 }
359         } else if (io->released == 0) {
360                 /*
361                  * Clean buffers can be generally released to the kernel.
362                  * We leave the bp passively associated with the HAMMER
363                  * structure and use bioops to disconnect it later on
364                  * if the kernel wants to discard the buffer.
365                  */
366                 if (bp->b_flags & B_LOCKED) {
367                         hammer_io_disassociate(iou, 1);
368                 } else {
369                         if (io->reclaim) {
370                                 hammer_io_disassociate(iou, 1);
371                         } else {
372                                 io->released = 1;
373                                 bqrelse(bp);
374                         }
375                 }
376         } else {
377                 /*
378                  * A released buffer is passively associate with our
379                  * hammer_io structure.  The kernel cannot destroy it
380                  * without making a bioops call.  If the kernel (B_LOCKED)
381                  * or we (reclaim) requested that the buffer be destroyed
382                  * we destroy it, otherwise we do a quick get/release to
383                  * reset its position in the kernel's LRU list.
384                  *
385                  * Leaving the buffer passively associated allows us to
386                  * use the kernel's LRU buffer flushing mechanisms rather
387                  * then rolling our own.
388                  */
389                 crit_enter();
390                 if (io->running == 0) {
391                         regetblk(bp);
392                         if ((bp->b_flags & B_LOCKED) || io->reclaim) {
393                                 io->released = 0;
394                                 hammer_io_disassociate(iou, 1);
395                         } else {
396                                 bqrelse(bp);
397                         }
398                 }
399                 crit_exit();
400         }
401 }
402
403 /*
404  * This routine is called with a locked IO when a flush is desired and
405  * no other references to the structure exists other then ours.  This
406  * routine is ONLY called when HAMMER believes it is safe to flush a
407  * potentially modified buffer out.
408  */
409 void
410 hammer_io_flush(struct hammer_io *io)
411 {
412         struct buf *bp;
413
414         /*
415          * Degenerate case - nothing to flush if nothing is dirty.
416          */
417         if (io->modified == 0) {
418                 return;
419         }
420
421         KKASSERT(io->bp);
422         KKASSERT(io->modify_refs <= 0);
423
424         /*
425          * Acquire ownership of the bp, particularly before we clear our
426          * modified flag.
427          *
428          * We are going to bawrite() this bp.  Don't leave a window where
429          * io->released is set, we actually own the bp rather then our
430          * buffer.
431          */
432         bp = io->bp;
433         if (io->released) {
434                 regetblk(bp);
435                 /* BUF_KERNPROC(io->bp); */
436                 /* io->released = 0; */
437                 KKASSERT(io->released);
438                 KKASSERT(io->bp == bp);
439         }
440         io->released = 1;
441
442         /*
443          * Acquire exclusive access to the bp and then clear the modified
444          * state of the buffer prior to issuing I/O to interlock any
445          * modifications made while the I/O is in progress.  This shouldn't
446          * happen anyway but losing data would be worse.  The modified bit
447          * will be rechecked after the IO completes.
448          *
449          * This is only legal when lock.refs == 1 (otherwise we might clear
450          * the modified bit while there are still users of the cluster
451          * modifying the data).
452          *
453          * Do this before potentially blocking so any attempt to modify the
454          * ondisk while we are blocked blocks waiting for us.
455          */
456         hammer_io_clear_modify(io);
457
458         /*
459          * Transfer ownership to the kernel and initiate I/O.
460          */
461         io->running = 1;
462         ++io->hmp->io_running_count;
463         bawrite(bp);
464 }
465
466 /************************************************************************
467  *                              BUFFER DIRTYING                         *
468  ************************************************************************
469  *
470  * These routines deal with dependancies created when IO buffers get
471  * modified.  The caller must call hammer_modify_*() on a referenced
472  * HAMMER structure prior to modifying its on-disk data.
473  *
474  * Any intent to modify an IO buffer acquires the related bp and imposes
475  * various write ordering dependancies.
476  */
477
478 /*
479  * Mark a HAMMER structure as undergoing modification.  Meta-data buffers
480  * are locked until the flusher can deal with them, pure data buffers
481  * can be written out.
482  */
483 static
484 void
485 hammer_io_modify(hammer_io_t io, int count)
486 {
487         struct hammer_mount *hmp = io->hmp;
488
489         /*
490          * io->modify_refs must be >= 0
491          */
492         while (io->modify_refs < 0) {
493                 io->waitmod = 1;
494                 tsleep(io, 0, "hmrmod", 0);
495         }
496
497         /*
498          * Shortcut if nothing to do.
499          */
500         KKASSERT(io->lock.refs != 0 && io->bp != NULL);
501         io->modify_refs += count;
502         if (io->modified && io->released == 0)
503                 return;
504
505         hammer_lock_ex(&io->lock);
506         if (io->modified == 0) {
507                 KKASSERT(io->mod_list == NULL);
508                 switch(io->type) {
509                 case HAMMER_STRUCTURE_VOLUME:
510                         io->mod_list = &hmp->volu_list;
511                         ++hmp->locked_dirty_count;
512                         ++hammer_count_dirtybufs;
513                         break;
514                 case HAMMER_STRUCTURE_META_BUFFER:
515                         io->mod_list = &hmp->meta_list;
516                         ++hmp->locked_dirty_count;
517                         ++hammer_count_dirtybufs;
518                         break;
519                 case HAMMER_STRUCTURE_UNDO_BUFFER:
520                         io->mod_list = &hmp->undo_list;
521                         break;
522                 case HAMMER_STRUCTURE_DATA_BUFFER:
523                         io->mod_list = &hmp->data_list;
524                         break;
525                 }
526                 TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry);
527                 io->modified = 1;
528         }
529         if (io->released) {
530                 regetblk(io->bp);
531                 BUF_KERNPROC(io->bp);
532                 io->released = 0;
533                 KKASSERT(io->modified != 0);
534         }
535         hammer_unlock(&io->lock);
536 }
537
538 static __inline
539 void
540 hammer_io_modify_done(hammer_io_t io)
541 {
542         KKASSERT(io->modify_refs > 0);
543         --io->modify_refs;
544         if (io->modify_refs == 0 && io->waitmod) {
545                 io->waitmod = 0;
546                 wakeup(io);
547         }
548 }
549
550 void
551 hammer_io_write_interlock(hammer_io_t io)
552 {
553         while (io->modify_refs != 0) {
554                 io->waitmod = 1;
555                 tsleep(io, 0, "hmrmod", 0);
556         }
557         io->modify_refs = -1;
558 }
559
560 void
561 hammer_io_done_interlock(hammer_io_t io)
562 {
563         KKASSERT(io->modify_refs == -1);
564         io->modify_refs = 0;
565         if (io->waitmod) {
566                 io->waitmod = 0;
567                 wakeup(io);
568         }
569 }
570
571 /*
572  * Caller intends to modify a volume's ondisk structure.
573  *
574  * This is only allowed if we are the flusher or we have a ref on the
575  * sync_lock.
576  */
577 void
578 hammer_modify_volume(hammer_transaction_t trans, hammer_volume_t volume,
579                      void *base, int len)
580 {
581         KKASSERT (trans == NULL || trans->sync_lock_refs > 0);
582
583         hammer_io_modify(&volume->io, 1);
584         if (len) {
585                 intptr_t rel_offset = (intptr_t)base - (intptr_t)volume->ondisk;
586                 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
587                 hammer_generate_undo(trans, &volume->io,
588                          HAMMER_ENCODE_RAW_VOLUME(volume->vol_no, rel_offset),
589                          base, len);
590         }
591 }
592
593 /*
594  * Caller intends to modify a buffer's ondisk structure.
595  *
596  * This is only allowed if we are the flusher or we have a ref on the
597  * sync_lock.
598  */
599 void
600 hammer_modify_buffer(hammer_transaction_t trans, hammer_buffer_t buffer,
601                      void *base, int len)
602 {
603         KKASSERT (trans == NULL || trans->sync_lock_refs > 0);
604
605         hammer_io_modify(&buffer->io, 1);
606         if (len) {
607                 intptr_t rel_offset = (intptr_t)base - (intptr_t)buffer->ondisk;
608                 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0);
609                 hammer_generate_undo(trans, &buffer->io,
610                                      buffer->zone2_offset + rel_offset,
611                                      base, len);
612         }
613 }
614
615 void
616 hammer_modify_volume_done(hammer_volume_t volume)
617 {
618         hammer_io_modify_done(&volume->io);
619 }
620
621 void
622 hammer_modify_buffer_done(hammer_buffer_t buffer)
623 {
624         hammer_io_modify_done(&buffer->io);
625 }
626
627 /*
628  * Mark an entity as not being dirty any more.
629  */
630 void
631 hammer_io_clear_modify(struct hammer_io *io)
632 {
633         if (io->modified) {
634                 KKASSERT(io->mod_list != NULL);
635                 if (io->mod_list == &io->hmp->volu_list ||
636                     io->mod_list == &io->hmp->meta_list) {
637                         --io->hmp->locked_dirty_count;
638                         --hammer_count_dirtybufs;
639                 }
640                 TAILQ_REMOVE(io->mod_list, io, mod_entry);
641                 io->mod_list = NULL;
642                 io->modified = 0;
643         }
644 }
645
646 /*
647  * Clear the IO's modify list.  Even though the IO is no longer modified
648  * it may still be on the lose_list.  This routine is called just before
649  * the governing hammer_buffer is destroyed.
650  */
651 void
652 hammer_io_clear_modlist(struct hammer_io *io)
653 {
654         if (io->mod_list) {
655                 KKASSERT(io->mod_list == &io->hmp->lose_list);
656                 TAILQ_REMOVE(io->mod_list, io, mod_entry);
657                 io->mod_list = NULL;
658         }
659 }
660
661 /************************************************************************
662  *                              HAMMER_BIOOPS                           *
663  ************************************************************************
664  *
665  */
666
667 /*
668  * Pre-IO initiation kernel callback - cluster build only
669  */
670 static void
671 hammer_io_start(struct buf *bp)
672 {
673 }
674
675 /*
676  * Post-IO completion kernel callback
677  *
678  * NOTE: HAMMER may modify a buffer after initiating I/O.  The modified bit
679  * may also be set if we were marking a cluster header open.  Only remove
680  * our dependancy if the modified bit is clear.
681  */
682 static void
683 hammer_io_complete(struct buf *bp)
684 {
685         union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
686
687         KKASSERT(iou->io.released == 1);
688
689         if (iou->io.running) {
690                 if (--iou->io.hmp->io_running_count == 0)
691                         wakeup(&iou->io.hmp->io_running_count);
692                 KKASSERT(iou->io.hmp->io_running_count >= 0);
693                 iou->io.running = 0;
694         }
695
696         /*
697          * If no lock references remain and we can acquire the IO lock and
698          * someone at some point wanted us to flush (B_LOCKED test), then
699          * try to dispose of the IO.
700          */
701         if (iou->io.waiting) {
702                 iou->io.waiting = 0;
703                 wakeup(iou);
704         }
705
706         /*
707          * Someone wanted us to flush, try to clean out the buffer. 
708          */
709         if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) {
710                 KKASSERT(iou->io.modified == 0);
711                 bp->b_flags &= ~B_LOCKED;
712                 hammer_io_deallocate(bp);
713                 /* structure may be dead now */
714         }
715 }
716
717 /*
718  * Callback from kernel when it wishes to deallocate a passively
719  * associated structure.  This mostly occurs with clean buffers
720  * but it may be possible for a holding structure to be marked dirty
721  * while its buffer is passively associated.
722  *
723  * If we cannot disassociate we set B_LOCKED to prevent the buffer
724  * from getting reused.
725  *
726  * WARNING: Because this can be called directly by getnewbuf we cannot
727  * recurse into the tree.  If a bp cannot be immediately disassociated
728  * our only recourse is to set B_LOCKED.
729  */
730 static void
731 hammer_io_deallocate(struct buf *bp)
732 {
733         hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep);
734
735         KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0);
736         if (iou->io.lock.refs > 0 || iou->io.modified) {
737                 /*
738                  * It is not legal to disassociate a modified buffer.  This
739                  * case really shouldn't ever occur.
740                  */
741                 bp->b_flags |= B_LOCKED;
742         } else {
743                 /*
744                  * Disassociate the BP.  If the io has no refs left we
745                  * have to add it to the loose list.
746                  */
747                 hammer_io_disassociate(iou, 0);
748                 if (iou->io.bp == NULL && 
749                     iou->io.type != HAMMER_STRUCTURE_VOLUME) {
750                         KKASSERT(iou->io.mod_list == NULL);
751                         iou->io.mod_list = &iou->io.hmp->lose_list;
752                         TAILQ_INSERT_TAIL(iou->io.mod_list, &iou->io, mod_entry);
753                 }
754         }
755 }
756
757 static int
758 hammer_io_fsync(struct vnode *vp)
759 {
760         return(0);
761 }
762
763 /*
764  * NOTE: will not be called unless we tell the kernel about the
765  * bioops.  Unused... we use the mount's VFS_SYNC instead.
766  */
767 static int
768 hammer_io_sync(struct mount *mp)
769 {
770         return(0);
771 }
772
773 static void
774 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
775 {
776 }
777
778 /*
779  * I/O pre-check for reading and writing.  HAMMER only uses this for
780  * B_CACHE buffers so checkread just shouldn't happen, but if it does
781  * allow it.
782  *
783  * Writing is a different case.  We don't want the kernel to try to write
784  * out a buffer that HAMMER may be modifying passively or which has a
785  * dependancy.  In addition, kernel-demanded writes can only proceed for
786  * certain types of buffers (i.e. UNDO and DATA types).  Other dirty
787  * buffer types can only be explicitly written by the flusher.
788  *
789  * checkwrite will only be called for bdwrite()n buffers.  If we return
790  * success the kernel is guaranteed to initiate the buffer write.
791  */
792 static int
793 hammer_io_checkread(struct buf *bp)
794 {
795         return(0);
796 }
797
798 static int
799 hammer_io_checkwrite(struct buf *bp)
800 {
801         hammer_io_t io = (void *)LIST_FIRST(&bp->b_dep);
802
803         /*
804          * This shouldn't happen under normal operation.
805          */
806         if (io->type == HAMMER_STRUCTURE_VOLUME ||
807             io->type == HAMMER_STRUCTURE_META_BUFFER) {
808                 if (!panicstr)
809                         panic("hammer_io_checkwrite: illegal buffer");
810                 bp->b_flags |= B_LOCKED;
811                 return(1);
812         }
813
814         /*
815          * We can only clear the modified bit if the IO is not currently
816          * undergoing modification.  Otherwise we may miss changes.
817          */
818         if (io->modify_refs == 0 && io->modified)
819                 hammer_io_clear_modify(io);
820
821         /*
822          * The kernel is going to start the IO, set io->running.
823          */
824         KKASSERT(io->running == 0);
825         io->running = 1;
826         ++io->hmp->io_running_count;
827         return(0);
828 }
829
830 /*
831  * Return non-zero if we wish to delay the kernel's attempt to flush
832  * this buffer to disk.
833  */
834 static int
835 hammer_io_countdeps(struct buf *bp, int n)
836 {
837         return(0);
838 }
839
840 struct bio_ops hammer_bioops = {
841         .io_start       = hammer_io_start,
842         .io_complete    = hammer_io_complete,
843         .io_deallocate  = hammer_io_deallocate,
844         .io_fsync       = hammer_io_fsync,
845         .io_sync        = hammer_io_sync,
846         .io_movedeps    = hammer_io_movedeps,
847         .io_countdeps   = hammer_io_countdeps,
848         .io_checkread   = hammer_io_checkread,
849         .io_checkwrite  = hammer_io_checkwrite,
850 };
851
852 /************************************************************************
853  *                              DIRECT IO OPS                           *
854  ************************************************************************
855  *
856  * These functions operate directly on the buffer cache buffer associated
857  * with a front-end vnode rather then a back-end device vnode.
858  */
859
860 /*
861  * Read a buffer associated with a front-end vnode directly from the
862  * disk media.  The bio may be issued asynchronously.
863  */
864 int
865 hammer_io_direct_read(hammer_mount_t hmp, hammer_btree_leaf_elm_t leaf,
866                       struct bio *bio)
867 {
868         hammer_off_t zone2_offset;
869         hammer_volume_t volume;
870         struct buf *bp;
871         struct bio *nbio;
872         int vol_no;
873         int error;
874
875         KKASSERT(leaf->data_offset >= HAMMER_ZONE_BTREE);
876         KKASSERT((leaf->data_offset & HAMMER_BUFMASK) == 0);
877         zone2_offset = hammer_blockmap_lookup(hmp, leaf->data_offset, &error);
878         if (error == 0) {
879                 vol_no = HAMMER_VOL_DECODE(zone2_offset);
880                 volume = hammer_get_volume(hmp, vol_no, &error);
881                 if (error == 0 && zone2_offset >= volume->maxbuf_off)
882                         error = EIO;
883                 if (error == 0) {
884                         zone2_offset &= HAMMER_OFF_SHORT_MASK;
885                         nbio = push_bio(bio);
886                         nbio->bio_offset = volume->ondisk->vol_buf_beg +
887                                            zone2_offset;
888                         vn_strategy(volume->devvp, nbio);
889                 }
890                 hammer_rel_volume(volume, 0);
891         }
892         if (error) {
893                 kprintf("hammer_direct_read: failed @ %016llx\n",
894                         leaf->data_offset);
895                 bp = bio->bio_buf;
896                 bp->b_error = error;
897                 bp->b_flags |= B_ERROR;
898                 biodone(bio);
899         }
900         return(error);
901 }
902
903 /*
904  * Write a buffer associated with a front-end vnode directly to the
905  * disk media.  The bio may be issued asynchronously.
906  */
907 int
908 hammer_io_direct_write(hammer_mount_t hmp, hammer_btree_leaf_elm_t leaf,
909                        struct bio *bio)
910 {
911         hammer_off_t buf_offset;
912         hammer_off_t zone2_offset;
913         hammer_volume_t volume;
914         hammer_buffer_t buffer;
915         struct buf *bp;
916         struct bio *nbio;
917         char *ptr;
918         int vol_no;
919         int error;
920
921         buf_offset = leaf->data_offset;
922
923         KKASSERT(buf_offset > HAMMER_ZONE_BTREE);
924         KKASSERT(bio->bio_buf->b_cmd == BUF_CMD_WRITE);
925
926         if ((buf_offset & HAMMER_BUFMASK) == 0 &&
927             leaf->data_len == HAMMER_BUFSIZE) {
928                 /*
929                  * We are using the vnode's bio to write directly to the
930                  * media, any hammer_buffer at the same zone-X offset will
931                  * now have stale data.
932                  */
933                 zone2_offset = hammer_blockmap_lookup(hmp, buf_offset, &error);
934                 vol_no = HAMMER_VOL_DECODE(zone2_offset);
935                 volume = hammer_get_volume(hmp, vol_no, &error);
936
937                 if (error == 0 && zone2_offset >= volume->maxbuf_off)
938                         error = EIO;
939                 if (error == 0) {
940                         hammer_del_buffers(hmp, buf_offset,
941                                            zone2_offset, HAMMER_BUFSIZE);
942                         bp = bio->bio_buf;
943                         KKASSERT(bp->b_bufsize == HAMMER_BUFSIZE);
944                         zone2_offset &= HAMMER_OFF_SHORT_MASK;
945
946                         nbio = push_bio(bio);
947                         nbio->bio_offset = volume->ondisk->vol_buf_beg +
948                                            zone2_offset;
949                         if (hammer_debug_write_release & 1)
950                                 nbio->bio_buf->b_flags |= B_RELBUF|B_NOCACHE;
951                         vn_strategy(volume->devvp, nbio);
952                 }
953                 hammer_rel_volume(volume, 0);
954         } else {
955                 KKASSERT(((buf_offset ^ (buf_offset + leaf->data_len - 1)) & ~HAMMER_BUFMASK64) == 0);
956                 buffer = NULL;
957                 ptr = hammer_bread(hmp, buf_offset, &error, &buffer);
958                 if (error == 0) {
959                         bp = bio->bio_buf;
960                         hammer_io_modify(&buffer->io, 1);
961                         bcopy(bp->b_data, ptr, leaf->data_len);
962                         hammer_io_modify_done(&buffer->io);
963                         hammer_rel_buffer(buffer, (hammer_debug_write_release & 2));
964                         bp->b_resid = 0;
965                         biodone(bio);
966                 }
967         }
968         if (error) {
969                 kprintf("hammer_direct_write: failed @ %016llx\n",
970                         leaf->data_offset);
971                 bp = bio->bio_buf;
972                 bp->b_resid = 0;
973                 bp->b_error = EIO;
974                 bp->b_flags |= B_ERROR;
975                 biodone(bio);
976         }
977         return(error);
978 }
979
980