b50267e4fb22a1cdd0c108571e738d0d99250ce4
[dragonfly.git] / sys / vfs / hammer / hammer_io.c
1 /*
2  * Copyright (c) 2007 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.15 2008/01/11 01:41:33 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_deallocate(struct buf *bp);
56 static int hammer_io_checkwrite(struct buf *bp);
57
58 /*
59  * Initialize an already-zero'd hammer_io structure
60  */
61 void
62 hammer_io_init(hammer_io_t io, enum hammer_io_type type)
63 {
64         io->type = type;
65         TAILQ_INIT(&io->deplist);
66 }
67
68 /*
69  * Helper routine to disassociate a buffer cache buffer from an I/O
70  * structure.  Called with the io structure exclusively locked.
71  *
72  * The io may have 0 or 1 references depending on who called us.  The
73  * caller is responsible for dealing with the refs.
74  *
75  * This call can only be made when no action is required on the buffer.
76  * HAMMER must own the buffer (released == 0) since mess around with it.
77  */
78 static void
79 hammer_io_disassociate(hammer_io_structure_t iou, int elseit)
80 {
81         struct buf *bp = iou->io.bp;
82
83         KKASSERT(TAILQ_EMPTY(&iou->io.deplist) && iou->io.modified == 0);
84         buf_dep_init(bp);
85         iou->io.bp = NULL;
86         if (elseit) {
87                 KKASSERT(iou->io.released == 0);
88                 iou->io.released = 1;
89                 bqrelse(bp);
90         } else {
91                 KKASSERT(iou->io.released);
92         }
93
94         switch(iou->io.type) {
95         case HAMMER_STRUCTURE_VOLUME:
96                 iou->volume.ondisk = NULL;
97                 iou->volume.alist.meta = NULL;
98                 break;
99         case HAMMER_STRUCTURE_SUPERCL:
100                 iou->supercl.ondisk = NULL;
101                 iou->supercl.alist.meta = NULL;
102                 break;
103         case HAMMER_STRUCTURE_CLUSTER:
104                 iou->cluster.ondisk = NULL;
105                 iou->cluster.alist_master.meta = NULL;
106                 iou->cluster.alist_btree.meta = NULL;
107                 iou->cluster.alist_record.meta = NULL;
108                 iou->cluster.alist_mdata.meta = NULL;
109                 break;
110         case HAMMER_STRUCTURE_BUFFER:
111                 iou->buffer.ondisk = NULL;
112                 iou->buffer.alist.meta = NULL;
113                 break;
114         }
115 }
116
117 /*
118  * Wait for any physical IO to complete
119  */
120 static void
121 hammer_io_wait(hammer_io_t io)
122 {
123         if (io->running) {
124                 crit_enter();
125                 tsleep_interlock(io);
126                 io->waiting = 1;
127                 for (;;) {
128                         tsleep(io, 0, "hmrflw", 0);
129                         if (io->running == 0)
130                                 break;
131                         tsleep_interlock(io);
132                         io->waiting = 1;
133                         if (io->running == 0)
134                                 break;
135                 }
136                 crit_exit();
137         }
138 }
139
140 void
141 hammer_io_waitdep(hammer_io_t io)
142 {
143         while (TAILQ_FIRST(&io->deplist)) {
144                 kprintf("waitdep %p\n", io);
145                 tsleep(io, 0, "hmrdep", hz);
146         }
147 }
148
149 /*
150  * Load bp for a HAMMER structure.  The io is exclusively locked by the
151  * caller.
152  */
153 int
154 hammer_io_read(struct vnode *devvp, struct hammer_io *io)
155 {
156         struct buf *bp;
157         int error;
158
159         if ((bp = io->bp) == NULL) {
160                 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp);
161                 if (error == 0) {
162                         bp = io->bp;
163                         bp->b_ops = &hammer_bioops;
164                         LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
165                         BUF_KERNPROC(bp);
166                 }
167                 io->modified = 0;       /* no new modifications yet */
168                 io->released = 0;       /* we hold an active lock on bp */
169                 io->running = 0;
170                 io->waiting = 0;
171         } else {
172                 error = 0;
173         }
174         return(error);
175 }
176
177 /*
178  * Similar to hammer_io_read() but returns a zero'd out buffer instead.
179  * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background
180  * I/O so we can call it.
181  *
182  * The caller is responsible for calling hammer_modify_*() on the appropriate
183  * HAMMER structure.
184  */
185 int
186 hammer_io_new(struct vnode *devvp, struct hammer_io *io)
187 {
188         struct buf *bp;
189
190         if ((bp = io->bp) == NULL) {
191                 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0);
192                 bp = io->bp;
193                 bp->b_ops = &hammer_bioops;
194                 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
195                 io->modified = 0;
196                 io->released = 0;
197                 io->running = 0;
198                 io->waiting = 0;
199                 BUF_KERNPROC(bp);
200         } else {
201                 if (io->released) {
202                         regetblk(bp);
203                         BUF_KERNPROC(bp);
204                         io->released = 0;
205                 }
206         }
207         vfs_bio_clrbuf(bp);
208         return(0);
209 }
210
211 /*
212  * This routine is called on the last reference to a hammer structure.
213  * The io is usually locked exclusively (but may not be during unmount).
214  *
215  * If flush is 1, or B_LOCKED was set indicating that the kernel
216  * wanted to recycle the buffer, and there are no dependancies, this
217  * function will issue an asynchronous write.
218  *
219  * If flush is 2 this function waits until all I/O has completed and
220  * disassociates the bp from the IO before returning, unless there
221  * are still other references.
222  */
223 void
224 hammer_io_release(struct hammer_io *io, int flush)
225 {
226         struct buf *bp;
227
228         if ((bp = io->bp) == NULL)
229                 return;
230
231 #if 0
232         /*
233          * If flush is 2 wait for dependancies
234          */
235         while (flush == 2 && TAILQ_FIRST(&io->deplist)) {
236                 hammer_io_wait(TAILQ_FIRST(&io->deplist));
237         }
238 #endif
239
240         /*
241          * Try to flush a dirty IO to disk if asked to by the caller
242          * or if the kernel tried to flush the buffer in the past.
243          *
244          * The flush will fail if any dependancies are present.
245          */
246         if (io->modified && (flush || bp->b_flags & B_LOCKED))
247                 hammer_io_flush(io);
248
249         /*
250          * If flush is 2 we wait for the IO to complete.
251          */
252         if (flush == 2 && io->running) {
253                 hammer_io_wait(io);
254         }
255
256         /*
257          * Actively or passively release the buffer.  Modified IOs with
258          * dependancies cannot be released.
259          */
260         if (flush && io->modified == 0 && io->running == 0) {
261                 KKASSERT(TAILQ_EMPTY(&io->deplist));
262                 if (io->released) {
263                         regetblk(bp);
264                         io->released = 0;
265                 }
266                 hammer_io_disassociate((hammer_io_structure_t)io, 1);
267         } else if (io->modified) {
268                 if (io->released == 0 && TAILQ_EMPTY(&io->deplist)) {
269                         io->released = 1;
270                         bdwrite(bp);
271                 }
272         } else if (io->released == 0) {
273                 io->released = 1;
274                 bqrelse(bp);
275         }
276 }
277
278 /*
279  * This routine is called with a locked IO when a flush is desired.
280  */
281 void
282 hammer_io_flush(struct hammer_io *io)
283 {
284         struct buf *bp;
285
286         /*
287          * Can't flush if the IO isn't modified or if it has dependancies.
288          */
289         if (io->modified == 0)
290                 return;
291         if (TAILQ_FIRST(&io->deplist))
292                 return;
293
294         KKASSERT(io->bp);
295
296         bp = io->bp;
297
298         /*
299          * If we are trying to flush a buffer we have to wait until the
300          * cluster header for the mark-OPEN has completed its I/O.
301          */
302         if (io->type == HAMMER_STRUCTURE_BUFFER) {
303                 hammer_io_structure_t iou = (void *)io;
304                 hammer_cluster_t cluster = iou->buffer.cluster;
305
306                 if (cluster->io.running) {
307                         kprintf("WAIT CLUSTER OPEN %d\n", cluster->clu_no);
308                         hammer_io_wait(&cluster->io);
309                         kprintf("WAIT CLUSTER OPEN OK\n");
310                 }
311         }
312         if (io->type == HAMMER_STRUCTURE_CLUSTER) {
313                 /*
314                  * Mark the cluster closed if we can
315                  */
316                 hammer_io_checkwrite(io->bp);
317         }
318         if (io->released) {
319                 regetblk(bp);
320                 /* BUF_KERNPROC(io->bp); */
321                 io->released = 0;
322         }
323         io->released = 1;
324         io->running = 1;
325         bawrite(bp);
326 }
327
328 /************************************************************************
329  *                              BUFFER DIRTYING                         *
330  ************************************************************************
331  *
332  * These routines deal with dependancies created when IO buffers get
333  * modified.  The caller must call hammer_modify_*() on a referenced
334  * HAMMER structure prior to modifying its on-disk data.
335  *
336  * Any intent to modify an IO buffer acquires the related bp and imposes
337  * various write ordering dependancies.
338  */
339
340 /*
341  * Ensure that the bp is acquired and return non-zero on a 0->1 transition
342  * of the modified bit.
343  */
344 static __inline
345 int
346 hammer_io_modify(hammer_io_t io, struct hammer_io_list *list)
347 {
348         int r = 0;
349
350         KKASSERT(io->lock.refs != 0 && io->bp != NULL);
351         if (io->modified == 0) {
352                 hammer_lock_ex(&io->lock);
353                 if (io->modified == 0) {
354                         if (io->released) {
355                                 regetblk(io->bp);
356                                 BUF_KERNPROC(io->bp);
357                                 io->released = 0;
358                         }
359                         io->modified = 1;
360                         io->entry_list = list;
361                         if (list)
362                                 TAILQ_INSERT_TAIL(list, io, entry);
363                         r = 1;
364                 }
365                 hammer_unlock(&io->lock);
366         } else if (io->released) {
367                 /*
368                  * Make sure no IO is occuring while we modify the contents
369                  * of the buffer. XXX should be able to avoid doing this.
370                  */
371                 hammer_lock_ex(&io->lock);
372                 if (io->released) {
373                         regetblk(io->bp);
374                         BUF_KERNPROC(io->bp);
375                         io->released = 0;
376                 }
377                 hammer_unlock(&io->lock);
378         }
379         return(r);
380 }
381
382 void
383 hammer_modify_volume(hammer_volume_t volume)
384 {
385         hammer_io_modify(&volume->io, NULL);
386 }
387
388 void
389 hammer_modify_supercl(hammer_supercl_t supercl)
390 {
391         hammer_io_modify(&supercl->io, &supercl->volume->io.deplist);
392 }
393
394 /*
395  * Caller intends to modify a cluster's ondisk structure. 
396  */
397 void
398 hammer_modify_cluster(hammer_cluster_t cluster)
399 {
400         hammer_io_modify(&cluster->io, &cluster->volume->io.deplist);
401 }
402
403 /*
404  * Caller intends to modify a buffer's ondisk structure.  The related
405  * cluster must be marked open prior to being able to flush the modified
406  * buffer so get that I/O going now.
407  */
408 void
409 hammer_modify_buffer(hammer_buffer_t buffer)
410 {
411         hammer_cluster_t cluster = buffer->cluster;
412
413         if (hammer_io_modify(&buffer->io, &cluster->io.deplist)) {
414                 hammer_modify_cluster(cluster);
415                 if ((cluster->ondisk->clu_flags & HAMMER_CLUF_OPEN) == 0) {
416                         hammer_lock_ex(&cluster->io.lock);
417                         if ((cluster->ondisk->clu_flags & HAMMER_CLUF_OPEN) == 0) {
418                                 KKASSERT(cluster->io.released == 0);
419                                 cluster->ondisk->clu_flags |= HAMMER_CLUF_OPEN;
420                                 cluster->io.released = 1;
421                                 cluster->io.running = 1;
422                                 bawrite(cluster->io.bp);
423                                 kprintf("OPEN CLUSTER %d:%d\n",
424                                         cluster->volume->vol_no,
425                                         cluster->clu_no);
426                         }
427                         hammer_unlock(&cluster->io.lock);
428                 }
429         }
430 }
431
432 /*
433  * Mark an entity as not being dirty any more -- this usually occurs when
434  * the governing a-list has freed the entire entity.
435  *
436  * XXX
437  */
438 void
439 hammer_io_clear_modify(struct hammer_io *io)
440 {
441 #if 0
442         struct buf *bp;
443
444         io->modified = 0;
445         if ((bp = io->bp) != NULL) {
446                 if (io->released) {
447                         regetblk(bp);
448                         /* BUF_KERNPROC(io->bp); */
449                 } else {
450                         io->released = 1;
451                 }
452                 if (io->modified == 0) {
453                         kprintf("hammer_io_clear_modify: cleared %p\n", io);
454                         bundirty(bp);
455                         bqrelse(bp);
456                 } else {
457                         bdwrite(bp);
458                 }
459         }
460 #endif
461 }
462
463 /************************************************************************
464  *                              HAMMER_BIOOPS                           *
465  ************************************************************************
466  *
467  */
468
469 /*
470  * Pre-IO initiation kernel callback - cluster build only
471  */
472 static void
473 hammer_io_start(struct buf *bp)
474 {
475 }
476
477 /*
478  * Post-IO completion kernel callback
479  */
480 static void
481 hammer_io_complete(struct buf *bp)
482 {
483         union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
484
485         KKASSERT(iou->io.released == 1);
486
487         if (iou->io.modified == 0)
488                 return;
489
490         /*
491          * If we were writing the cluster header out and CLUF_OPEN is set,
492          * do NOT clear the modify bit.  Just clear the IO running bit
493          * and do a wakeup.
494          */
495         if (iou->io.type == HAMMER_STRUCTURE_CLUSTER) {
496                 if (iou->cluster.ondisk->clu_flags & HAMMER_CLUF_OPEN) {
497                         iou->io.running = 0;
498                         if (iou->io.waiting) {
499                                 iou->io.waiting = 0;
500                                 wakeup(iou);
501                         }
502                         return;
503                 }
504         }
505          
506
507         /*
508          * If this was a write then clear the modified status and remove us
509          * from the dependancy list.
510          *
511          * If no lock references remain and we can acquire the IO lock and
512          * someone at some point wanted us to flush (B_LOCKED test), then
513          * try to dispose of the IO.
514          */
515         iou->io.modified = 0;
516         if (iou->io.entry_list) {
517                 TAILQ_REMOVE(iou->io.entry_list, &iou->io, entry);
518                 iou->io.entry_list = NULL;
519         }
520         iou->io.running = 0;
521         if (iou->io.waiting) {
522                 iou->io.waiting = 0;
523                 wakeup(iou);
524         }
525
526         /*
527          * Someone wanted us to flush, try to clean out the buffer. 
528          */
529         if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) {
530                 hammer_io_deallocate(bp);
531                 /* structure may be dead now */
532         }
533 }
534
535 /*
536  * Callback from kernel when it wishes to deallocate a passively
537  * associated structure.  This case can only occur with read-only
538  * bp's.
539  *
540  * If we cannot disassociate we set B_LOCKED to prevent the buffer
541  * from getting reused.
542  */
543 static void
544 hammer_io_deallocate(struct buf *bp)
545 {
546         hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep);
547
548         KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0);
549         if (iou->io.modified) {
550                 bp->b_flags |= B_LOCKED;
551                 return;
552         }
553         hammer_ref(&iou->io.lock);
554         if (iou->io.lock.refs > 1 || iou->io.modified) {
555                 hammer_unref(&iou->io.lock);
556                 bp->b_flags |= B_LOCKED;
557         } else {
558                 hammer_io_disassociate(iou, 0);
559
560                 switch(iou->io.type) {
561                 case HAMMER_STRUCTURE_VOLUME:
562                         hammer_rel_volume(&iou->volume, 1);
563                         break;
564                 case HAMMER_STRUCTURE_SUPERCL:
565                         hammer_rel_supercl(&iou->supercl, 1);
566                         break;
567                 case HAMMER_STRUCTURE_CLUSTER:
568                         hammer_rel_cluster(&iou->cluster, 1);
569                         break;
570                 case HAMMER_STRUCTURE_BUFFER:
571                         hammer_rel_buffer(&iou->buffer, 1);
572                         break;
573                 }
574         }
575 }
576
577 static int
578 hammer_io_fsync(struct vnode *vp)
579 {
580         return(0);
581 }
582
583 /*
584  * NOTE: will not be called unless we tell the kernel about the
585  * bioops.  Unused... we use the mount's VFS_SYNC instead.
586  */
587 static int
588 hammer_io_sync(struct mount *mp)
589 {
590         return(0);
591 }
592
593 static void
594 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
595 {
596 }
597
598 /*
599  * I/O pre-check for reading and writing.  HAMMER only uses this for
600  * B_CACHE buffers so checkread just shouldn't happen, but if it does
601  * allow it.
602  *
603  * Writing is a different case.  We don't want the kernel to try to write
604  * out a buffer that HAMMER may be modifying passively or which has a
605  * dependancy.
606  *
607  * This code enforces the following write ordering: buffers, then cluster
608  * headers, then volume headers.
609  */
610 static int
611 hammer_io_checkread(struct buf *bp)
612 {
613         return(0);
614 }
615
616 static int
617 hammer_io_checkwrite(struct buf *bp)
618 {
619         union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
620
621         /*
622          * A modified cluster with no dependancies can be closed.
623          */
624         if (iou->io.type == HAMMER_STRUCTURE_CLUSTER && iou->io.modified) {
625                 hammer_cluster_t cluster = &iou->cluster;
626
627                 if (TAILQ_EMPTY(&cluster->io.deplist)) {
628                         cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN;
629                         kprintf("CLOSE CLUSTER %d:%d\n",
630                                 cluster->volume->vol_no,
631                                 cluster->clu_no);
632                 }
633         }
634         return(0);
635 }
636
637 /*
638  * Return non-zero if the caller should flush the structure associated
639  * with this io sub-structure.
640  */
641 int
642 hammer_io_checkflush(struct hammer_io *io)
643 {
644         if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) {
645                 return(1);
646         }
647         return(0);
648 }
649
650 /*
651  * Return non-zero if we wish to delay the kernel's attempt to flush
652  * this buffer to disk.
653  */
654 static int
655 hammer_io_countdeps(struct buf *bp, int n)
656 {
657         return(0);
658 }
659
660 struct bio_ops hammer_bioops = {
661         .io_start       = hammer_io_start,
662         .io_complete    = hammer_io_complete,
663         .io_deallocate  = hammer_io_deallocate,
664         .io_fsync       = hammer_io_fsync,
665         .io_sync        = hammer_io_sync,
666         .io_movedeps    = hammer_io_movedeps,
667         .io_countdeps   = hammer_io_countdeps,
668         .io_checkread   = hammer_io_checkread,
669         .io_checkwrite  = hammer_io_checkwrite,
670 };
671