2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.5 2007/11/27 07:48:52 dillon Exp $
37 * IO Primitives and buffer cache management
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
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
50 #include <sys/fcntl.h>
51 #include <sys/nlookup.h>
56 * Helper routine which disassociates a buffer cache buf from a
59 * If the io structures indicates that the buffer is not in a released
60 * state we must dispose of it.
63 hammer_io_disassociate(union hammer_io_structure *io)
65 struct buf *bp = io->io.bp;
69 LIST_INIT(&bp->b_dep); /* clear the association */
72 modified = io->io.modified;
73 released = io->io.released;
76 case HAMMER_STRUCTURE_VOLUME:
77 io->volume.ondisk = NULL;
78 io->volume.alist.meta = NULL;
81 case HAMMER_STRUCTURE_SUPERCL:
82 io->supercl.ondisk = NULL;
83 io->supercl.alist.meta = NULL;
86 case HAMMER_STRUCTURE_CLUSTER:
87 io->cluster.ondisk = NULL;
88 io->cluster.alist_master.meta = NULL;
89 io->cluster.alist_btree.meta = NULL;
90 io->cluster.alist_record.meta = NULL;
91 io->cluster.alist_mdata.meta = NULL;
94 case HAMMER_STRUCTURE_BUFFER:
95 io->buffer.ondisk = NULL;
96 io->buffer.alist.meta = NULL;
101 * 'io' now invalid. If the buffer was not released we have to
104 * disassociate can be called via hammer_io_checkwrite() with
105 * the buffer in a released state (possibly with no lock held
106 * at all, in fact). Don't mess with it if we are in a released
119 * Load bp for a HAMMER structure.
122 hammer_io_read(struct vnode *devvp, struct hammer_io *io)
127 if ((bp = io->bp) == NULL) {
128 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp);
131 bp->b_ops = &hammer_bioops;
132 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
135 io->modified = 0; /* no new modifications yet */
136 io->released = 0; /* we hold an active lock on bp */
144 * Similar to hammer_io_read() but returns a zero'd out buffer instead.
145 * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background
146 * I/O so we can call it.
149 hammer_io_new(struct vnode *devvp, struct hammer_io *io)
153 if ((bp = io->bp) == NULL) {
154 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0);
156 bp->b_ops = &hammer_bioops;
157 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node);
158 io->released = 0; /* we hold an active lock on bp */
173 * Release the IO buffer on the last reference to a hammer structure. At
174 * this time the lock still has a reference.
176 * We flush and disassociate the bp if flush is non-zero or if the kernel
177 * tried to free/reuse the buffer.
180 hammer_io_release(struct hammer_io *io, int flush)
182 union hammer_io_structure *iou = (void *)io;
185 if ((bp = io->bp) != NULL) {
186 if (bp->b_flags & B_LOCKED) {
188 * The kernel wanted the buffer but couldn't get it,
191 KKASSERT(io->released);
195 bp->b_flags &= ~B_LOCKED;
196 hammer_io_disassociate(iou);
197 } else if (io->released == 0) {
199 * We are holding a real lock on the buffer, release
200 * it passively (hammer_io_deallocate is called
201 * when the kernel really wants to reuse the buffer).
204 hammer_io_disassociate(iou);
213 } else if (io->modified && (bp->b_flags & B_DELWRI) == 0) {
215 * We are holding the buffer passively but made
216 * modifications to it. The kernel has not initiated
217 * I/O (else B_LOCKED would have been set), so just
218 * check whether B_DELWRI is set. Since we still
219 * have lock references on the HAMMER structure the
220 * kernel cannot throw the buffer away.
222 * We have to do this to avoid the situation where
223 * the buffer is not marked B_DELWRI when modified
224 * and in a released state, otherwise the kernel
225 * will never try to flush the modified buffer!
231 hammer_io_disassociate(iou);
239 * We are holding the buffer passively but were
240 * asked to disassociate and flush it.
245 hammer_io_disassociate(iou);
246 /* io->released ignored */
247 } /* else just leave it associated in a released state */
256 * Pre and post I/O callbacks. No buffer munging is done so there is
257 * nothing to do here.
259 static void hammer_io_deallocate(struct buf *bp);
262 hammer_io_start(struct buf *bp)
267 hammer_io_complete(struct buf *bp)
272 * Callback from kernel when it wishes to deallocate a passively
273 * associated structure. This can only occur if the buffer is
274 * passively associated with the structure. The kernel has locked
277 * If we cannot disassociate we set B_LOCKED to prevent the buffer
278 * from getting reused.
281 hammer_io_deallocate(struct buf *bp)
283 union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep);
285 /* XXX memory interlock, spinlock to sync cpus */
287 KKASSERT(io->io.released);
291 * First, ref the structure to prevent either the buffer or the
292 * structure from going away or being unexpectedly flushed.
294 hammer_ref(&io->io.lock);
297 * Buffers can have active references from cached hammer_node's,
298 * even if those nodes are themselves passively cached. Attempt
299 * to clean them out. This may not succeed.
301 if (io->io.type == HAMMER_STRUCTURE_BUFFER &&
302 hammer_lock_ex_try(&io->io.lock) == 0) {
303 hammer_flush_buffer_nodes(&io->buffer);
304 hammer_unlock(&io->io.lock);
307 if (hammer_islastref(&io->io.lock)) {
309 * If we are the only ref left we can disassociate the
310 * I/O. It had better still be in a released state because
311 * the kernel is holding a lock on the buffer.
313 KKASSERT(io->io.released);
314 hammer_io_disassociate(io);
315 bp->b_flags &= ~B_LOCKED;
318 * Perform final rights on the structure. This can cause
319 * a chain reaction - e.g. last buffer -> last cluster ->
320 * last supercluster -> last volume.
322 switch(io->io.type) {
323 case HAMMER_STRUCTURE_VOLUME:
324 hammer_rel_volume(&io->volume, 1);
326 case HAMMER_STRUCTURE_SUPERCL:
327 hammer_rel_supercl(&io->supercl, 1);
329 case HAMMER_STRUCTURE_CLUSTER:
330 hammer_rel_cluster(&io->cluster, 1);
332 case HAMMER_STRUCTURE_BUFFER:
333 hammer_rel_buffer(&io->buffer, 1);
338 * Otherwise tell the kernel not to destroy the buffer.
340 * We have to unref the structure without performing any
341 * final rights to it to avoid a deadlock.
343 bp->b_flags |= B_LOCKED;
344 hammer_unref(&io->io.lock);
351 hammer_io_fsync(struct vnode *vp)
357 * NOTE: will not be called unless we tell the kernel about the
358 * bioops. Unused... we use the mount's VFS_SYNC instead.
361 hammer_io_sync(struct mount *mp)
367 hammer_io_movedeps(struct buf *bp1, struct buf *bp2)
372 * I/O pre-check for reading and writing. HAMMER only uses this for
373 * B_CACHE buffers so checkread just shouldn't happen, but if it does
376 * Writing is a different case. We don't want to write out a buffer
377 * that HAMMER may be modifying passively.
380 hammer_io_checkread(struct buf *bp)
386 hammer_io_checkwrite(struct buf *bp)
388 union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep);
390 if (io->io.lock.refs) {
391 bp->b_flags |= B_LOCKED;
394 KKASSERT(bp->b_flags & B_DELWRI);
395 hammer_io_disassociate(io);
401 * Return non-zero if the caller should flush the structure associated
402 * with this io sub-structure.
405 hammer_io_checkflush(struct hammer_io *io)
407 if (io->bp == NULL || (io->bp->b_flags & B_LOCKED))
413 * Return non-zero if we wish to delay the kernel's attempt to flush
414 * this buffer to disk.
417 hammer_io_countdeps(struct buf *bp, int n)
422 struct bio_ops hammer_bioops = {
423 .io_start = hammer_io_start,
424 .io_complete = hammer_io_complete,
425 .io_deallocate = hammer_io_deallocate,
426 .io_fsync = hammer_io_fsync,
427 .io_sync = hammer_io_sync,
428 .io_movedeps = hammer_io_movedeps,
429 .io_countdeps = hammer_io_countdeps,
430 .io_checkread = hammer_io_checkread,
431 .io_checkwrite = hammer_io_checkwrite,