HAMMER 15/many - user utility infrastructure, refactor alists, misc
[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.12 2008/01/03 06:48:49 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 /*
56  * Helper routine to disassociate a buffer cache buffer from an I/O
57  * structure.
58  */
59 static void
60 hammer_io_disassociate(union hammer_io_structure *io)
61 {
62         struct buf *bp = io->io.bp;
63
64         KKASSERT(io->io.released && io->io.modified == 0);
65         LIST_INIT(&bp->b_dep);  /* clear the association */
66         bp->b_ops = NULL;
67         io->io.bp = NULL;
68         bp->b_flags &= ~B_LOCKED;
69
70         switch(io->io.type) {
71         case HAMMER_STRUCTURE_VOLUME:
72                 io->volume.ondisk = NULL;
73                 io->volume.alist.meta = NULL;
74                 break;
75         case HAMMER_STRUCTURE_SUPERCL:
76                 io->supercl.ondisk = NULL;
77                 io->supercl.alist.meta = NULL;
78                 break;
79         case HAMMER_STRUCTURE_CLUSTER:
80                 io->cluster.ondisk = NULL;
81                 io->cluster.alist_master.meta = NULL;
82                 io->cluster.alist_btree.meta = NULL;
83                 io->cluster.alist_record.meta = NULL;
84                 io->cluster.alist_mdata.meta = NULL;
85                 break;
86         case HAMMER_STRUCTURE_BUFFER:
87                 io->buffer.ondisk = NULL;
88                 io->buffer.alist.meta = NULL;
89                 break;
90         }
91 }
92
93 /*
94  * Mark a cluster as being closed.  This is done as late as possible,
95  * only when we are asked to flush the cluster
96  */
97 static void
98 hammer_close_cluster(hammer_cluster_t cluster)
99 {
100         while (cluster->state == HAMMER_CLUSTER_ASYNC)
101                 tsleep(cluster, 0, "hmrdep", 0);
102         if (cluster->state == HAMMER_CLUSTER_OPEN) {
103                 cluster->state = HAMMER_CLUSTER_IDLE;
104                 hammer_modify_cluster(cluster);
105                 cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN;
106                 hammer_modify_cluster_done(cluster);
107                 kprintf("CLOSE CLUSTER\n");
108         }
109 }
110
111 /*
112  * Hack XXX - called from kernel syncer via hammer_io_checkwrite() when it
113  * wants to flush buffer.
114  */
115 static void
116 hammer_close_cluster_quick(hammer_cluster_t cluster)
117 {
118         if (cluster->state == HAMMER_CLUSTER_OPEN) {
119                 cluster->state = HAMMER_CLUSTER_IDLE;
120                 cluster->io.modified = 1;
121                 cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN;
122                 kprintf("CLOSE CLUSTER ON KERNEL WRITE\n");
123         }
124 }
125
126
127 /*
128  * Load bp for a HAMMER structure.
129  */
130 int
131 hammer_io_read(struct vnode *devvp, struct hammer_io *io)
132 {
133         struct buf *bp;
134         int error;
135
136         if ((bp = io->bp) == NULL) {
137                 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp);
138                 if (error == 0) {
139                         bp = io->bp;
140                         bp->b_ops = &hammer_bioops;
141                         LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
142                         BUF_KERNPROC(bp);
143                 }
144                 io->modified = 0;       /* no new modifications yet */
145                 io->released = 0;       /* we hold an active lock on bp */
146         } else {
147                 error = 0;
148         }
149         return(error);
150 }
151
152 /*
153  * Similar to hammer_io_read() but returns a zero'd out buffer instead.
154  * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background
155  * I/O so we can call it.
156  */
157 int
158 hammer_io_new(struct vnode *devvp, struct hammer_io *io)
159 {
160         struct buf *bp;
161
162         if ((bp = io->bp) == NULL) {
163                 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0);
164                 bp = io->bp;
165                 bp->b_ops = &hammer_bioops;
166                 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
167                 io->released = 0;       /* we hold an active lock on bp */
168                 BUF_KERNPROC(bp);
169         } else {
170                 if (io->released) {
171                         regetblk(bp);
172                         BUF_KERNPROC(bp);
173                         io->released = 0;
174                 }
175         }
176         io->modified = 1;
177         vfs_bio_clrbuf(bp);
178         return(0);
179 }
180
181 /*
182  * This routine is called when a buffer within a cluster is modified.  We
183  * mark the cluster open and immediately initiate asynchronous I/O.  Any
184  * related hammer_buffer write I/O blocks until our async write completes.
185  * This guarentees (inasmuch as the OS can) that the cluster recovery code
186  * will see a cluster marked open if a crash occured while the filesystem
187  * still had dirty buffers associated with that cluster.
188  *
189  * XXX
190  */
191 void
192 hammer_io_notify_cluster(hammer_cluster_t cluster)
193 {
194         struct hammer_io *io = &cluster->io;
195
196         if (cluster->state == HAMMER_CLUSTER_IDLE) {
197                 hammer_lock_ex(&cluster->io.lock);
198                 if (cluster->state == HAMMER_CLUSTER_IDLE) {
199                         if (io->released)
200                                 regetblk(io->bp);
201                         else
202                                 io->released = 1;
203                         kprintf("MARK CLUSTER OPEN\n");
204                         cluster->ondisk->clu_flags |= HAMMER_CLUF_OPEN;
205                         cluster->state = HAMMER_CLUSTER_ASYNC;
206                         cluster->io.modified = 1;
207                         bawrite(io->bp);
208                 }
209                 hammer_unlock(&cluster->io.lock);
210         }
211 }
212
213 /*
214  * This routine is called on the last reference to a hammer structure.
215  * Regardless of the state io->modified must be cleared when we return.
216  *
217  * If flush is non-zero we have to completely disassociate the bp from the
218  * structure (which may involve blocking).  Otherwise we can leave the bp
219  * passively associated with the structure.
220  *
221  * The caller is holding io->lock exclusively.
222  */
223 void
224 hammer_io_release(struct hammer_io *io, int flush)
225 {
226         union hammer_io_structure *iou = (void *)io;
227         hammer_cluster_t cluster;
228         struct buf *bp;
229         int modified;
230
231         if ((bp = io->bp) != NULL) {
232                 /*
233                  * If neither we nor the kernel want to flush the bp, we can
234                  * stop here.  Make sure the bp is passively released
235                  * before returning.  Even though we are still holding it,
236                  * we want to be notified when the kernel wishes to flush
237                  * it out so make sure B_DELWRI is properly set if we had
238                  * made modifications.
239                  */
240                 if (flush == 0 && (bp->b_flags & B_LOCKED) == 0) {
241                         if ((bp->b_flags & B_DELWRI) == 0 && io->modified) {
242                                 if (io->released)
243                                         regetblk(bp);
244                                 else
245                                         io->released = 1;
246                                 io->modified = 0;
247                                 bdwrite(bp);
248                         } else if (io->released == 0) {
249                                 /* buffer write state already synchronized */
250                                 io->modified = 0;
251                                 io->released = 1;
252                                 bqrelse(bp);
253                         } else {
254                                 /* buffer write state already synchronized */
255                                 io->modified = 0;
256                         }
257                         return;
258                 }
259
260                 /*
261                  * Either we want to flush the buffer or the kernel tried.
262                  *
263                  * If this is a hammer_buffer we may have to wait for the
264                  * cluster header write to complete.
265                  */
266                 if (iou->io.type == HAMMER_STRUCTURE_BUFFER &&
267                     (io->modified || (bp->b_flags & B_DELWRI))) {
268                         cluster = iou->buffer.cluster;
269                         while (cluster->state == HAMMER_CLUSTER_ASYNC)
270                                 tsleep(iou->buffer.cluster, 0, "hmrdep", 0);
271                 }
272
273                 /*
274                  * If we have an open cluster header, close it
275                  */
276                 if (iou->io.type == HAMMER_STRUCTURE_CLUSTER) {
277                         hammer_close_cluster(&iou->cluster);
278                 }
279
280                 /*
281                  * Gain ownership of the buffer.  Nothing can take it away
282                  * from the io structure while we have it locked, so we
283                  * can safely reget.
284                  *
285                  * Once our thread owns the buffer we can disassociate it
286                  * from the io structure.
287                  */
288                 if (io->released)
289                         regetblk(bp);
290                 else
291                         io->released = 1;
292                 modified = io->modified;
293                 io->modified = 0;
294                 hammer_io_disassociate(iou);
295
296                 /*
297                  * Now dispose of the buffer.  Someone tried to flush, so
298                  * issue the I/O immediately.
299                  */
300                 if (modified || (bp->b_flags & B_DELWRI))
301                         bawrite(bp);
302                 else
303                         bqrelse(bp);
304         }
305 }
306
307 /*
308  * Flush dirty data, if any.
309  */
310 void
311 hammer_io_flush(struct hammer_io *io, struct hammer_sync_info *info)
312 {
313         struct buf *bp;
314         int error;
315
316 again:
317         if ((bp = io->bp) == NULL)
318                 return;
319         if (bp->b_flags & B_DELWRI)
320                 io->modified = 1;
321
322         /*
323          * We can't initiate a write while the buffer is being modified
324          * by someone.
325          */
326         while (io->lock.modifying) {
327                 io->lock.wanted = 1;
328                 kprintf("DELAYING IO FLUSH BP %p TYPE %d REFS %d modifying %d\n",
329                         bp, io->type, io->lock.refs, io->lock.modifying);
330                 tsleep(&io->lock, 0, "hmrfls", 0);
331         }
332         hammer_lock_ex(&io->lock);
333         if (io->lock.modifying || io->bp == NULL) {
334                 hammer_unlock(&io->lock);
335                 goto again;
336         }
337
338         /*
339          * Acquire ownership of the buffer cache buffer so we can flush it
340          * out.
341          */
342         if (io->released) {
343                 if (io->modified == 0)
344                         goto done;
345                 regetblk(bp);
346         } else {
347                 io->released = 1;
348         }
349
350         /*
351          * Return the bp to the system, issuing I/O if necessary.  The
352          * system will issue a callback to us when it actually wants to
353          * throw the bp away.
354          */
355         if (io->modified == 0) {
356                 bqrelse(bp);
357         } else if (info->waitfor & MNT_WAIT) {
358                 io->modified = 0;
359                 error = bwrite(bp);
360                 if (error)
361                         info->error = error;
362         } else {
363                 io->modified = 0;
364                 bawrite(bp);
365         }
366 done:
367         hammer_unlock(&io->lock);
368 }
369
370 /*
371  * Called prior to any modifications being made to ondisk data.  This
372  * forces the caller to wait for any writes to complete.  We explicitly
373  * avoid the write-modify race.
374  *
375  * This routine is only called on hammer structures which are already
376  * actively referenced.
377  */
378 void
379 hammer_io_intend_modify(struct hammer_io *io)
380 {
381         KKASSERT(io->lock.refs != 0 && io->bp != NULL);
382         if (io->released) {
383                 hammer_lock_ex(&io->lock);
384                 if (io->released) {
385                         regetblk(io->bp);
386                         BUF_KERNPROC(io->bp);
387                         io->released = 0;
388                 }
389                 hammer_unlock(&io->lock);
390         }
391 }
392
393 void
394 hammer_io_modify_done(struct hammer_io *io)
395 {
396         KKASSERT(io->lock.modifying > 0);
397         --io->lock.modifying;
398         if (io->lock.wanted && io->lock.modifying == 0) {
399                 io->lock.wanted = 0;
400                 wakeup(&io->lock);
401         }
402 }
403
404 /*
405  * Mark an entity as not being dirty any more -- usually occurs when
406  * the governing a-list has freed the entire entity.
407  */
408 void
409 hammer_io_clear_modify(struct hammer_io *io)
410 {
411         struct buf *bp;
412
413         io->modified = 0;
414         if ((bp = io->bp) != NULL) {
415                 if (io->released)
416                         regetblk(bp);
417                 else
418                         io->released = 1;
419                 if (io->modified == 0) {
420                         kprintf("hammer_io_clear_modify: cleared %p\n", io);
421                         bundirty(bp);
422                         bqrelse(bp);
423                 } else {
424                         bdwrite(bp);
425                 }
426         }
427 }
428
429 /*
430  * HAMMER_BIOOPS
431  */
432
433 /*
434  * Pre and post I/O callbacks.
435  */
436 static void hammer_io_deallocate(struct buf *bp);
437
438 static void
439 hammer_io_start(struct buf *bp)
440 {
441 #if 0
442         union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep);
443
444         if (io->io.type == HAMMER_STRUCTURE_BUFFER) {
445                 while (io->buffer.cluster->io_in_progress) {
446                         kprintf("hammer_io_start: wait for cluster\n");
447                         tsleep(io->buffer.cluster, 0, "hmrdep", 0);
448                         kprintf("hammer_io_start: wait for cluster done\n");
449                 }
450         }
451 #endif
452 }
453
454 static void
455 hammer_io_complete(struct buf *bp)
456 {
457         union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep);
458
459         if (io->io.type == HAMMER_STRUCTURE_CLUSTER) {
460                 if (io->cluster.state == HAMMER_CLUSTER_ASYNC) {
461                         io->cluster.state = HAMMER_CLUSTER_OPEN;
462                         wakeup(&io->cluster);
463                 }
464         }
465 }
466
467 /*
468  * Callback from kernel when it wishes to deallocate a passively
469  * associated structure.  This can only occur if the buffer is
470  * passively associated with the structure.  The kernel has locked
471  * the buffer.
472  *
473  * If we cannot disassociate we set B_LOCKED to prevent the buffer
474  * from getting reused.
475  */
476 static void
477 hammer_io_deallocate(struct buf *bp)
478 {
479         union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep);
480
481         /* XXX memory interlock, spinlock to sync cpus */
482
483         /*
484          * Since the kernel is passing us a locked buffer, the HAMMER
485          * structure had better not believe it has a lock on the buffer.
486          */
487         KKASSERT(io->io.released);
488         crit_enter();
489
490         /*
491          * First, ref the structure to prevent either the buffer or the
492          * structure from going away or being unexpectedly flushed.
493          */
494         hammer_ref(&io->io.lock);
495
496         /*
497          * Buffers can have active references from cached hammer_node's,
498          * even if those nodes are themselves passively cached.  Attempt
499          * to clean them out.  This may not succeed.
500          *
501          * We have to do some magic with io.released because
502          * hammer_io_intend_modify() can be called indirectly from the
503          * flush code, otherwise we might panic with a recursive bp lock.
504          */
505         if (io->io.type == HAMMER_STRUCTURE_BUFFER &&
506             hammer_lock_ex_try(&io->io.lock) == 0) {
507                 io->io.released = 0;
508                 hammer_flush_buffer_nodes(&io->buffer);
509                 KKASSERT(io->io.released == 0);
510                 io->io.released = 1;
511                 hammer_unlock(&io->io.lock);
512         }
513
514         if (hammer_islastref(&io->io.lock)) {
515                 /*
516                  * If we are the only ref left we can disassociate the I/O.
517                  * It had better still be in a released state because the
518                  * kernel is holding a lock on the buffer.  Any passive
519                  * modifications should have already been synchronized with
520                  * the buffer.
521                  */
522                 KKASSERT(io->io.modified == 0);
523                 hammer_io_disassociate(io);
524
525                 /*
526                  * Perform final rights on the structure.  This can cause
527                  * a chain reaction - e.g. last buffer -> last cluster ->
528                  * last supercluster -> last volume.
529                  */
530                 switch(io->io.type) {
531                 case HAMMER_STRUCTURE_VOLUME:
532                         hammer_rel_volume(&io->volume, 1);
533                         break;
534                 case HAMMER_STRUCTURE_SUPERCL:
535                         hammer_rel_supercl(&io->supercl, 1);
536                         break;
537                 case HAMMER_STRUCTURE_CLUSTER:
538                         hammer_rel_cluster(&io->cluster, 1);
539                         break;
540                 case HAMMER_STRUCTURE_BUFFER:
541                         hammer_rel_buffer(&io->buffer, 1);
542                         break;
543                 }
544         } else {
545                 /*
546                  * Otherwise tell the kernel not to destroy the buffer.
547                  * 
548                  * We have to unref the structure without performing any
549                  * final rights to it to avoid a deadlock.
550                  */
551                 bp->b_flags |= B_LOCKED;
552                 hammer_unref(&io->io.lock);
553         }
554         crit_exit();
555 }
556
557 static int
558 hammer_io_fsync(struct vnode *vp)
559 {
560         return(0);
561 }
562
563 /*
564  * NOTE: will not be called unless we tell the kernel about the
565  * bioops.  Unused... we use the mount's VFS_SYNC instead.
566  */
567 static int
568 hammer_io_sync(struct mount *mp)
569 {
570         return(0);
571 }
572
573 static void
574 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
575 {
576 }
577
578 /*
579  * I/O pre-check for reading and writing.  HAMMER only uses this for
580  * B_CACHE buffers so checkread just shouldn't happen, but if it does
581  * allow it.
582  *
583  * Writing is a different case.  We don't want the kernel to try to write
584  * out a buffer that HAMMER may be modifying passively or which has a
585  * dependancy.
586  *
587  * This code enforces the following write ordering: buffers, then cluster
588  * headers, then volume headers.
589  */
590 static int
591 hammer_io_checkread(struct buf *bp)
592 {
593         return(0);
594 }
595
596 static int
597 hammer_io_checkwrite(struct buf *bp)
598 {
599         union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep);
600
601         if (iou->io.type == HAMMER_STRUCTURE_BUFFER &&
602             iou->buffer.cluster->state == HAMMER_CLUSTER_ASYNC) {
603                 /*
604                  * Cannot write out a cluster buffer if the cluster header
605                  * I/O opening the cluster has not completed.
606                  */
607                 bp->b_flags |= B_LOCKED;
608                 return(-1);
609         } else if (iou->io.lock.refs) {
610                 /*
611                  * Cannot write out a bp if its associated buffer has active
612                  * references.
613                  */
614                 bp->b_flags |= B_LOCKED;
615                 return(-1);
616         } else {
617                 /*
618                  * We're good, but before we can let the kernel proceed we
619                  * may have to make some adjustments.
620                  *
621                  * Since there are no refs on the io structure, HAMMER must
622                  * have already synchronized its modify state with the bp
623                  * so iou->io.modified should be 0.
624                  */
625                 if (iou->io.type == HAMMER_STRUCTURE_CLUSTER)
626                         hammer_close_cluster_quick(&iou->cluster);
627                 hammer_io_disassociate(iou);
628                 return(0);
629         }
630 }
631
632 /*
633  * Return non-zero if the caller should flush the structure associated
634  * with this io sub-structure.
635  */
636 int
637 hammer_io_checkflush(struct hammer_io *io)
638 {
639         if (io->bp == NULL || (io->bp->b_flags & B_LOCKED))
640                 return(1);
641         return(0);
642 }
643
644 /*
645  * Return non-zero if we wish to delay the kernel's attempt to flush
646  * this buffer to disk.
647  */
648 static int
649 hammer_io_countdeps(struct buf *bp, int n)
650 {
651         return(0);
652 }
653
654 struct bio_ops hammer_bioops = {
655         .io_start       = hammer_io_start,
656         .io_complete    = hammer_io_complete,
657         .io_deallocate  = hammer_io_deallocate,
658         .io_fsync       = hammer_io_fsync,
659         .io_sync        = hammer_io_sync,
660         .io_movedeps    = hammer_io_movedeps,
661         .io_countdeps   = hammer_io_countdeps,
662         .io_checkread   = hammer_io_checkread,
663         .io_checkwrite  = hammer_io_checkwrite,
664 };
665