1 /* $NetBSD: udf_strat_rmw.c,v 1.27 2015/10/06 08:57:34 hannken Exp $ */
4 * Copyright (c) 2006, 2008 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: udf_strat_rmw.c,v 1.27 2015/10/06 08:57:34 hannken Exp $");
35 #if defined(_KERNEL_OPT)
36 #include "opt_compat_netbsd.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sysctl.h>
42 #include <sys/namei.h>
44 #include <sys/kernel.h>
45 #include <sys/vnode.h>
46 #include <miscfs/genfs/genfs_node.h>
47 #include <sys/mount.h>
50 #include <sys/device.h>
51 #include <sys/disklabel.h>
52 #include <sys/ioctl.h>
53 #include <sys/malloc.h>
54 #include <sys/dirent.h>
57 #include <sys/kauth.h>
58 #include <sys/kthread.h>
59 #include <dev/clock_subr.h>
61 #include <fs/udf/ecma167-udf.h>
62 #include <fs/udf/udf_mount.h>
66 #include "udf_bswap.h"
69 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
70 #define PRIV(ump) ((struct strat_private *) (ump)->strategy_private)
71 #define BTOE(buf) ((struct udf_eccline *) ((buf)->b_private))
73 /* --------------------------------------------------------------------- */
75 #define UDF_MAX_PACKET_SIZE 64 /* DONT change this */
78 #define UDF_SHED_WAITING 1 /* waiting on timeout */
79 #define UDF_SHED_READING 2
80 #define UDF_SHED_WRITING 3
81 #define UDF_SHED_SEQWRITING 4
82 #define UDF_SHED_IDLE 5 /* refcnt'd */
83 #define UDF_SHED_FREE 6 /* recycleable */
84 #define UDF_SHED_MAX 6+1
87 #define ECC_LOCKED 0x01 /* prevent access */
88 #define ECC_WANTED 0x02 /* trying access */
89 #define ECC_SEQWRITING 0x04 /* sequential queue */
90 #define ECC_FLOATING 0x08 /* not queued yet */
92 #define ECC_WAITTIME 10
95 TAILQ_HEAD(ecclineq
, udf_eccline
);
97 struct udf_mount
*ump
;
98 uint64_t present
; /* preserve these */
99 uint64_t readin
; /* bitmap */
100 uint64_t dirty
; /* bitmap */
101 uint64_t error
; /* bitmap */
104 struct timespec wait_time
;
106 uint32_t start_sector
; /* physical */
114 struct buf
*bufs
[UDF_MAX_PACKET_SIZE
];
115 uint32_t bufs_bpos
[UDF_MAX_PACKET_SIZE
];
116 int bufs_len
[UDF_MAX_PACKET_SIZE
];
118 int queued_on
; /* on which BUFQ list */
119 LIST_ENTRY(udf_eccline
) hashchain
; /* on sector lookup */
123 struct strat_private
{
125 kcondvar_t discstrat_cv
; /* to wait on */
126 kmutex_t discstrat_mutex
; /* disc strategy */
127 kmutex_t seqwrite_mutex
; /* protect mappings */
129 int thread_running
; /* thread control */
130 int run_thread
; /* thread control */
131 int thread_finished
; /* thread control */
135 int num_queued
[UDF_SHED_MAX
];
136 struct bufq_state
*queues
[UDF_SHED_MAX
];
137 struct timespec last_queued
[UDF_SHED_MAX
];
138 struct disk_strategy old_strategy_setting
;
140 struct pool eccline_pool
;
141 struct pool ecclineblob_pool
;
142 LIST_HEAD(, udf_eccline
) eccline_hash
[UDF_ECCBUF_HASHSIZE
];
145 /* --------------------------------------------------------------------- */
147 #define UDF_LOCK_ECCLINE(eccline) udf_lock_eccline(eccline, __FILE__, __LINE__)
148 #define UDF_UNLOCK_ECCLINE(eccline) udf_unlock_eccline(eccline, __FILE__, __LINE__)
150 /* can be called with or without discstrat lock */
152 udf_lock_eccline(struct udf_eccline
*eccline
, const char *fname
, int sline
)
154 struct strat_private
*priv
= PRIV(eccline
->ump
);
157 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
159 waslocked
= mutex_owned(&priv
->discstrat_mutex
);
161 mutex_enter(&priv
->discstrat_mutex
);
163 /* wait until its unlocked first */
165 while (eccline
->flags
& ECC_LOCKED
) {
166 DPRINTF(ECCLINE
, ("waiting for lock at %s:%d\n",
168 DPRINTF(ECCLINE
, ("was locked at %s:%d\n",
169 eccline
->fname
, eccline
->sline
));
170 eccline
->flags
|= ECC_WANTED
;
171 ret
= cv_timedwait(&priv
->discstrat_cv
, &priv
->discstrat_mutex
,
173 if (ret
== EWOULDBLOCK
)
174 DPRINTF(LOCKING
, ("eccline lock helt, waiting for "
177 eccline
->flags
|= ECC_LOCKED
;
178 eccline
->flags
&= ~ECC_WANTED
;
181 eccline
->fname
= fname
;
182 eccline
->sline
= sline
;
185 mutex_exit(&priv
->discstrat_mutex
);
189 /* can be called with or without discstrat lock */
191 udf_unlock_eccline(struct udf_eccline
*eccline
, const char *fname
, int sline
)
193 struct strat_private
*priv
= PRIV(eccline
->ump
);
196 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
198 waslocked
= mutex_owned(&priv
->discstrat_mutex
);
200 mutex_enter(&priv
->discstrat_mutex
);
202 eccline
->flags
&= ~ECC_LOCKED
;
203 cv_broadcast(&priv
->discstrat_cv
);
206 mutex_exit(&priv
->discstrat_mutex
);
210 /* NOTE discstrat_mutex should be held! */
212 udf_dispose_eccline(struct udf_eccline
*eccline
)
214 struct strat_private
*priv
= PRIV(eccline
->ump
);
216 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
218 DPRINTF(ECCLINE
, ("dispose eccline with start sector %d, "
219 "present %0"PRIx64
"\n", eccline
->start_sector
,
222 KASSERT(eccline
->refcnt
== 0);
223 KASSERT(eccline
->dirty
== 0);
224 KASSERT(eccline
->queued_on
== 0);
225 KASSERT(eccline
->flags
& ECC_FLOATING
);
226 KASSERT(eccline
->flags
& ECC_LOCKED
);
228 LIST_REMOVE(eccline
, hashchain
);
229 priv
->num_floating
--;
231 putiobuf(eccline
->buf
);
232 pool_put(&priv
->ecclineblob_pool
, eccline
->blob
);
233 pool_put(&priv
->eccline_pool
, eccline
);
237 /* NOTE discstrat_mutex should be held! */
239 udf_push_eccline(struct udf_eccline
*eccline
, int newqueue
)
241 struct strat_private
*priv
= PRIV(eccline
->ump
);
243 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
245 DPRINTF(PARANOIA
, ("DEBUG: buf %p pushed on queue %d\n", eccline
->buf
, newqueue
));
247 KASSERT(eccline
->queued_on
== 0);
248 KASSERT(eccline
->flags
& ECC_FLOATING
);
250 /* set buffer block numbers to make sure its queued correctly */
251 eccline
->buf
->b_lblkno
= eccline
->start_sector
;
252 eccline
->buf
->b_blkno
= eccline
->start_sector
;
253 eccline
->buf
->b_rawblkno
= eccline
->start_sector
;
255 vfs_timestamp(&priv
->last_queued
[newqueue
]);
256 eccline
->flags
&= ~ECC_FLOATING
;
257 priv
->num_floating
--;
258 eccline
->queued_on
= newqueue
;
259 priv
->num_queued
[newqueue
]++;
260 bufq_put(priv
->queues
[newqueue
], eccline
->buf
);
262 UDF_UNLOCK_ECCLINE(eccline
);
264 /* XXX tickle disc strategy statemachine */
265 if (newqueue
!= UDF_SHED_IDLE
)
266 cv_signal(&priv
->discstrat_cv
);
270 static struct udf_eccline
*
271 udf_peek_eccline(struct strat_private
*priv
, int queued_on
)
273 struct udf_eccline
*eccline
;
276 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
279 buf
= bufq_peek(priv
->queues
[queued_on
]);
280 /* could have been a race, but we'll revisit later */
285 UDF_LOCK_ECCLINE(eccline
);
287 /* might have changed before we obtained the lock */
288 if (eccline
->queued_on
== queued_on
)
291 UDF_UNLOCK_ECCLINE(eccline
);
294 KASSERT(eccline
->queued_on
== queued_on
);
295 KASSERT((eccline
->flags
& ECC_FLOATING
) == 0);
297 DPRINTF(PARANOIA
, ("DEBUG: buf %p peeked at queue %d\n",
298 eccline
->buf
, queued_on
));
304 static struct udf_eccline
*
305 udf_pop_eccline(struct strat_private
*priv
, int queued_on
)
307 struct udf_eccline
*eccline
;
310 KASSERT(mutex_owned(&priv
->discstrat_mutex
));
313 buf
= bufq_get(priv
->queues
[queued_on
]);
315 // KASSERT(priv->num_queued[queued_on] == 0);
320 UDF_LOCK_ECCLINE(eccline
);
322 /* might have changed before we obtained the lock */
323 if (eccline
->queued_on
== queued_on
)
326 UDF_UNLOCK_ECCLINE(eccline
);
329 KASSERT(eccline
->queued_on
== queued_on
);
330 KASSERT((eccline
->flags
& ECC_FLOATING
) == 0);
332 priv
->num_queued
[queued_on
]--;
333 eccline
->queued_on
= 0;
335 eccline
->flags
|= ECC_FLOATING
;
336 priv
->num_floating
++;
338 DPRINTF(PARANOIA
, ("DEBUG: buf %p popped from queue %d\n",
339 eccline
->buf
, queued_on
));
346 udf_unqueue_eccline(struct strat_private
*priv
, struct udf_eccline
*eccline
)
348 struct buf
*ret __diagused
;
350 UDF_LOCK_ECCLINE(eccline
);
351 if (eccline
->queued_on
== 0) {
352 KASSERT(eccline
->flags
& ECC_FLOATING
);
356 ret
= bufq_cancel(priv
->queues
[eccline
->queued_on
], eccline
->buf
);
357 KASSERT(ret
== eccline
->buf
);
359 priv
->num_queued
[eccline
->queued_on
]--;
360 eccline
->queued_on
= 0;
362 eccline
->flags
|= ECC_FLOATING
;
363 priv
->num_floating
++;
367 static struct udf_eccline
*
368 udf_geteccline(struct udf_mount
*ump
, uint32_t sector
, int flags
)
370 struct strat_private
*priv
= PRIV(ump
);
371 struct udf_eccline
*eccline
;
372 uint32_t start_sector
, lb_size
, blobsize
;
373 uint8_t *eccline_blob
;
374 int line
, line_offset
;
377 mutex_enter(&priv
->discstrat_mutex
);
379 /* lookup in our line cache hashtable */
380 line_offset
= sector
% ump
->packet_size
;
381 start_sector
= sector
- line_offset
;
382 line
= (start_sector
/ump
->packet_size
) & UDF_ECCBUF_HASHMASK
;
384 KASSERT(priv
->thread_running
);
387 DPRINTF(ECCLINE
, ("get line sector %d, line %d\n", sector
, line
));
388 LIST_FOREACH(eccline
, &priv
->eccline_hash
[line
], hashchain
) {
389 if (eccline
->start_sector
== start_sector
) {
390 DPRINTF(ECCLINE
, ("\tfound eccline, start_sector %d\n",
391 eccline
->start_sector
));
392 udf_unqueue_eccline(priv
, eccline
);
394 mutex_exit(&priv
->discstrat_mutex
);
399 /* not found in eccline cache */
400 DPRINTF(ECCLINE
, ("\tnot found in eccline cache\n"));
402 lb_size
= udf_rw32(ump
->logical_vol
->lb_size
);
403 blobsize
= ump
->packet_size
* lb_size
;
405 /* dont allow too many pending requests */
406 DPRINTF(ECCLINE
, ("\tallocating new eccline\n"));
407 num_busy
= (priv
->num_queued
[UDF_SHED_SEQWRITING
] + priv
->num_floating
);
408 if ((flags
& ECC_SEQWRITING
) && (num_busy
> UDF_ECCLINE_MAXBUSY
)) {
409 cv_timedwait(&priv
->discstrat_cv
,
410 &priv
->discstrat_mutex
, hz
/8);
414 eccline_blob
= pool_get(&priv
->ecclineblob_pool
, PR_NOWAIT
);
415 eccline
= pool_get(&priv
->eccline_pool
, PR_NOWAIT
);
416 if ((eccline_blob
== NULL
) || (eccline
== NULL
)) {
418 pool_put(&priv
->ecclineblob_pool
, eccline_blob
);
420 pool_put(&priv
->eccline_pool
, eccline
);
422 /* out of memory for now; canibalise freelist */
423 eccline
= udf_pop_eccline(priv
, UDF_SHED_FREE
);
424 if (eccline
== NULL
) {
425 /* serious trouble; wait and retry */
426 cv_timedwait(&priv
->discstrat_cv
,
427 &priv
->discstrat_mutex
, hz
/8);
431 /* push back line if we're waiting for it or its locked */
432 if (eccline
->flags
& ECC_WANTED
) {
433 /* we won a race, but someone else needed it */
434 udf_push_eccline(eccline
, UDF_SHED_FREE
);
438 /* unlink this entry */
439 LIST_REMOVE(eccline
, hashchain
);
440 KASSERT(eccline
->flags
& ECC_FLOATING
);
441 KASSERT(eccline
->queued_on
== 0);
443 eccline_blob
= eccline
->blob
;
444 eccline
->flags
= ECC_FLOATING
| ECC_LOCKED
;
446 eccline
->flags
= ECC_FLOATING
| ECC_LOCKED
;
447 priv
->num_floating
++;
450 eccline
->queued_on
= 0;
451 eccline
->blob
= eccline_blob
;
452 eccline
->buf
= getiobuf(NULL
, true);
453 eccline
->buf
->b_private
= eccline
; /* IMPORTANT */
455 /* initialise eccline blob */
456 /* XXX memset expensive and strictly not needed XXX */
457 memset(eccline
->blob
, 0, blobsize
);
460 eccline
->present
= eccline
->readin
= eccline
->dirty
= 0;
463 memset(eccline
->bufs
, 0, UDF_MAX_PACKET_SIZE
* sizeof(struct buf
*));
465 eccline
->start_sector
= start_sector
;
466 eccline
->buf
->b_lblkno
= start_sector
;
467 eccline
->buf
->b_blkno
= start_sector
;
468 eccline
->buf
->b_rawblkno
= start_sector
;
470 LIST_INSERT_HEAD(&priv
->eccline_hash
[line
], eccline
, hashchain
);
473 * TODO possible optimalisation for checking overlap with partitions
474 * to get a clue on future eccline usage
477 KASSERT(eccline
->refcnt
== 0);
478 KASSERT(eccline
->flags
& ECC_FLOATING
);
479 KASSERT(eccline
->flags
& ECC_LOCKED
);
480 mutex_exit(&priv
->discstrat_mutex
);
487 udf_puteccline(struct udf_eccline
*eccline
)
489 struct strat_private
*priv
= PRIV(eccline
->ump
);
490 struct udf_mount
*ump
= eccline
->ump
;
491 uint64_t allbits
= ((uint64_t) 1 << ump
->packet_size
)-1;
494 mutex_enter(&priv
->discstrat_mutex
);
496 DPRINTF(ECCLINE
, ("put eccline start sector %d, refcnt %d\n",
497 eccline
->start_sector
, eccline
->refcnt
));
499 KASSERT(eccline
->flags
& ECC_LOCKED
);
500 KASSERT(eccline
->flags
& ECC_FLOATING
);
502 /* clear all read bits that are already read in */
503 if (eccline
->readin
& eccline
->present
)
504 eccline
->readin
&= (~eccline
->present
) & allbits
;
506 /* if we have active nodes we dont set it on seqwriting */
507 if (eccline
->refcnt
> 1)
508 eccline
->flags
&= ~ECC_SEQWRITING
;
511 new_queue
= UDF_SHED_FREE
;
512 if (eccline
->refcnt
> 0)
513 new_queue
= UDF_SHED_IDLE
;
514 if (eccline
->flags
& ECC_WANTED
)
515 new_queue
= UDF_SHED_IDLE
;
517 new_queue
= UDF_SHED_READING
;
518 if (eccline
->dirty
) {
519 new_queue
= UDF_SHED_WAITING
;
520 vfs_timestamp(&eccline
->wait_time
);
521 eccline
->wait_time
.tv_sec
+= ECC_WAITTIME
;
523 if (eccline
->present
== allbits
) {
524 new_queue
= UDF_SHED_WRITING
;
525 if (eccline
->flags
& ECC_SEQWRITING
)
526 new_queue
= UDF_SHED_SEQWRITING
;
529 udf_push_eccline(eccline
, new_queue
);
531 mutex_exit(&priv
->discstrat_mutex
);
534 /* --------------------------------------------------------------------- */
537 udf_create_nodedscr_rmw(struct udf_strat_args
*args
)
539 union dscrptr
**dscrptr
= &args
->dscr
;
540 struct udf_mount
*ump
= args
->ump
;
541 struct long_ad
*icb
= args
->icb
;
542 struct udf_eccline
*eccline
;
544 uint32_t sectornr
, lb_size
, dummy
;
548 error
= udf_translate_vtop(ump
, icb
, §ornr
, &dummy
);
552 lb_size
= udf_rw32(ump
->logical_vol
->lb_size
);
554 /* get our eccline */
555 eccline
= udf_geteccline(ump
, sectornr
, 0);
556 eccsect
= sectornr
- eccline
->start_sector
;
558 bit
= (uint64_t) 1 << eccsect
;
559 eccline
->readin
&= ~bit
; /* just in case */
560 eccline
->present
|= bit
;
561 eccline
->dirty
&= ~bit
; /* Err... euhm... clean? */
566 mem
= ((uint8_t *) eccline
->blob
) + eccsect
* lb_size
;
567 memset(mem
, 0, lb_size
);
569 udf_puteccline(eccline
);
571 *dscrptr
= (union dscrptr
*) mem
;
577 udf_free_nodedscr_rmw(struct udf_strat_args
*args
)
579 struct udf_mount
*ump
= args
->ump
;
580 struct long_ad
*icb
= args
->icb
;
581 struct udf_eccline
*eccline
;
583 uint32_t sectornr
, dummy
;
586 error
= udf_translate_vtop(ump
, icb
, §ornr
, &dummy
);
590 /* get our eccline */
591 eccline
= udf_geteccline(ump
, sectornr
, 0);
592 eccsect
= sectornr
- eccline
->start_sector
;
594 bit
= (uint64_t) 1 << eccsect
;
595 KASSERT(eccline
->present
& bit
);
597 eccline
->readin
&= ~bit
; /* just in case */
598 /* XXX eccline->dirty? */
600 KASSERT(eccline
->refcnt
>= 1);
603 udf_puteccline(eccline
);
608 udf_read_nodedscr_rmw(struct udf_strat_args
*args
)
610 union dscrptr
**dscrptr
= &args
->dscr
;
611 struct udf_mount
*ump
= args
->ump
;
612 struct long_ad
*icb
= args
->icb
;
613 struct strat_private
*priv
;
614 struct udf_eccline
*eccline
;
616 uint32_t sectornr
, dummy
;
618 int sector_size
= ump
->discinfo
.sector_size
;
619 int lb_size __diagused
= udf_rw32(ump
->logical_vol
->lb_size
);
620 int i
, error
, dscrlen
, eccsect
;
622 KASSERT(sector_size
== lb_size
);
623 error
= udf_translate_vtop(ump
, icb
, §ornr
, &dummy
);
627 /* get our eccline */
628 eccline
= udf_geteccline(ump
, sectornr
, 0);
629 eccsect
= sectornr
- eccline
->start_sector
;
631 bit
= (uint64_t) 1 << eccsect
;
632 if ((eccline
->present
& bit
) == 0) {
633 /* mark bit for readin */
634 eccline
->readin
|= bit
;
635 eccline
->refcnt
++; /* prevent recycling */
636 KASSERT(eccline
->bufs
[eccsect
] == NULL
);
637 udf_puteccline(eccline
);
639 /* wait for completion */
640 priv
= PRIV(eccline
->ump
);
641 mutex_enter(&priv
->discstrat_mutex
);
642 while (((eccline
->present
| eccline
->error
) & bit
) == 0) {
643 error
= cv_timedwait(&priv
->discstrat_cv
,
644 &priv
->discstrat_mutex
,
646 if (error
== EWOULDBLOCK
)
647 DPRINTF(LOCKING
, ("eccline waiting for read\n"));
649 mutex_exit(&priv
->discstrat_mutex
);
652 eccline
= udf_geteccline(ump
, sectornr
, 0);
653 KASSERT(eccline
->refcnt
>= 1);
654 eccline
->refcnt
--; /* undo refcnt */
656 if (eccline
->error
& bit
) {
658 udf_puteccline(eccline
);
659 return EIO
; /* XXX error code */
663 *dscrptr
= (union dscrptr
*)
664 (((uint8_t *) eccline
->blob
) + eccsect
* sector_size
);
666 /* code from read_phys_descr */
667 /* check if its a valid tag */
668 error
= udf_check_tag(*dscrptr
);
670 /* check if its an empty block */
671 pos
= (uint8_t *) *dscrptr
;
672 for (i
= 0; i
< sector_size
; i
++, pos
++) {
675 if (i
== sector_size
) {
676 /* return no error but with no dscrptr */
680 udf_puteccline(eccline
);
684 /* calculate descriptor size */
685 dscrlen
= udf_tagsize(*dscrptr
, sector_size
);
686 error
= udf_check_tag_payload(*dscrptr
, dscrlen
);
689 udf_puteccline(eccline
);
693 /* we have a hold since it has a node descriptor */
695 udf_puteccline(eccline
);
702 udf_write_nodedscr_rmw(struct udf_strat_args
*args
)
704 union dscrptr
*dscrptr
= args
->dscr
;
705 struct udf_mount
*ump
= args
->ump
;
706 struct long_ad
*icb
= args
->icb
;
707 struct udf_node
*udf_node
= args
->udf_node
;
708 struct udf_eccline
*eccline
;
710 uint32_t sectornr
, logsectornr
, dummy
;
711 // int waitfor = args->waitfor;
712 int sector_size
= ump
->discinfo
.sector_size
;
713 int lb_size __diagused
= udf_rw32(ump
->logical_vol
->lb_size
);
716 KASSERT(sector_size
== lb_size
);
718 error
= udf_translate_vtop(ump
, icb
, §ornr
, &dummy
);
722 /* get our eccline */
723 eccline
= udf_geteccline(ump
, sectornr
, 0);
724 eccsect
= sectornr
- eccline
->start_sector
;
726 bit
= (uint64_t) 1 << eccsect
;
728 /* old callback still pending? */
729 if (eccline
->bufs
[eccsect
]) {
730 DPRINTF(WRITE
, ("udf_write_nodedscr_rmw: writing descriptor"
732 nestiobuf_done(eccline
->bufs
[eccsect
],
733 eccline
->bufs_len
[eccsect
],
735 eccline
->bufs
[eccsect
] = NULL
;
738 /* set sector number in the descriptor and validate */
739 dscrptr
= (union dscrptr
*)
740 (((uint8_t *) eccline
->blob
) + eccsect
* sector_size
);
741 KASSERT(dscrptr
== args
->dscr
);
743 logsectornr
= udf_rw32(icb
->loc
.lb_num
);
744 dscrptr
->tag
.tag_loc
= udf_rw32(logsectornr
);
745 udf_validate_tag_and_crc_sums(dscrptr
);
747 udf_fixup_node_internals(ump
, (uint8_t *) dscrptr
, UDF_C_NODE
);
750 KASSERT(eccline
->present
& bit
);
751 eccline
->dirty
|= bit
;
753 KASSERT(udf_tagsize(dscrptr
, sector_size
) <= sector_size
);
755 udf_node
->outstanding_nodedscr
--;
756 if (udf_node
->outstanding_nodedscr
== 0) {
757 /* XXX still using wakeup! */
758 UDF_UNLOCK_NODE(udf_node
, 0);
759 wakeup(&udf_node
->outstanding_nodedscr
);
761 udf_puteccline(eccline
);
763 /* XXX waitfor not used */
769 udf_queuebuf_rmw(struct udf_strat_args
*args
)
771 struct udf_mount
*ump
= args
->ump
;
772 struct buf
*buf
= args
->nestbuf
;
773 struct desc_tag
*tag
;
774 struct strat_private
*priv
= PRIV(ump
);
775 struct udf_eccline
*eccline
;
776 struct long_ad
*node_ad_cpy
;
777 uint64_t bit
, *lmapping
, *pmapping
, *lmappos
, *pmappos
, blknr
;
778 uint32_t buf_len
, len
, sectors
, sectornr
, our_sectornr
;
781 uint8_t *fidblk
, *src
, *dst
;
782 int sector_size
= ump
->discinfo
.sector_size
;
783 int blks
= sector_size
/ DEV_BSIZE
;
784 int eccsect
, what
, queue
, error
;
788 KASSERT(buf
->b_iodone
== nestiobuf_iodone
);
790 blknr
= buf
->b_blkno
;
791 our_sectornr
= blknr
/ blks
;
793 what
= buf
->b_udf_c_type
;
794 queue
= UDF_SHED_READING
;
795 if ((buf
->b_flags
& B_READ
) == 0) {
797 queue
= UDF_SHED_SEQWRITING
;
798 if (what
== UDF_C_ABSOLUTE
)
799 queue
= UDF_SHED_WRITING
;
800 if (what
== UDF_C_DSCR
)
801 queue
= UDF_SHED_WRITING
;
802 if (what
== UDF_C_NODE
)
803 queue
= UDF_SHED_WRITING
;
806 if (queue
== UDF_SHED_READING
) {
807 DPRINTF(SHEDULE
, ("\nudf_queuebuf_rmw READ %p : sector %d type %d,"
808 "b_resid %d, b_bcount %d, b_bufsize %d\n",
809 buf
, (uint32_t) buf
->b_blkno
/ blks
, buf
->b_udf_c_type
,
810 buf
->b_resid
, buf
->b_bcount
, buf
->b_bufsize
));
812 /* mark bits for reading */
813 buf_len
= buf
->b_bcount
;
814 sectornr
= our_sectornr
;
815 eccline
= udf_geteccline(ump
, sectornr
, 0);
816 eccsect
= sectornr
- eccline
->start_sector
;
819 len
= MIN(buf_len
, sector_size
);
820 if ((eccsect
< 0) || (eccsect
>= ump
->packet_size
)) {
821 udf_puteccline(eccline
);
822 eccline
= udf_geteccline(ump
, sectornr
, 0);
823 eccsect
= sectornr
- eccline
->start_sector
;
825 bit
= (uint64_t) 1 << eccsect
;
826 error
= eccline
->error
& bit
? EIO
: 0;
827 if (eccline
->present
& bit
) {
828 src
= (uint8_t *) eccline
->blob
+
829 eccsect
* sector_size
;
830 dst
= (uint8_t *) buf
->b_data
+ bpos
;
832 memcpy(dst
, src
, len
);
833 nestiobuf_done(buf
, len
, error
);
835 eccline
->readin
|= bit
;
836 KASSERT(eccline
->bufs
[eccsect
] == NULL
);
837 eccline
->bufs
[eccsect
] = buf
;
838 eccline
->bufs_bpos
[eccsect
] = bpos
;
839 eccline
->bufs_len
[eccsect
] = len
;
846 udf_puteccline(eccline
);
850 if (queue
== UDF_SHED_WRITING
) {
851 DPRINTF(SHEDULE
, ("\nudf_queuebuf_rmw WRITE %p : sector %d "
852 "type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
853 buf
, (uint32_t) buf
->b_blkno
/ blks
, buf
->b_udf_c_type
,
854 buf
->b_resid
, buf
->b_bcount
, buf
->b_bufsize
));
856 /* if we have FIDs fixup using buffer's sector number(s) */
857 if (buf
->b_udf_c_type
== UDF_C_FIDS
)
858 panic("UDF_C_FIDS in SHED_WRITING!\n");
860 udf_fixup_node_internals(ump
, buf
->b_data
, buf
->b_udf_c_type
);
862 /* copy parts into the bufs and set for writing */
863 buf_len
= buf
->b_bcount
;
864 sectornr
= our_sectornr
;
865 eccline
= udf_geteccline(ump
, sectornr
, 0);
866 eccsect
= sectornr
- eccline
->start_sector
;
869 len
= MIN(buf_len
, sector_size
);
870 if ((eccsect
< 0) || (eccsect
>= ump
->packet_size
)) {
871 udf_puteccline(eccline
);
872 eccline
= udf_geteccline(ump
, sectornr
, 0);
873 eccsect
= sectornr
- eccline
->start_sector
;
875 bit
= (uint64_t) 1 << eccsect
;
876 KASSERT((eccline
->readin
& bit
) == 0);
877 eccline
->present
|= bit
;
878 eccline
->dirty
|= bit
;
879 if (eccline
->bufs
[eccsect
]) {
880 /* old callback still pending */
881 nestiobuf_done(eccline
->bufs
[eccsect
],
882 eccline
->bufs_len
[eccsect
],
884 eccline
->bufs
[eccsect
] = NULL
;
887 src
= (uint8_t *) buf
->b_data
+ bpos
;
888 dst
= (uint8_t *) eccline
->blob
+ eccsect
* sector_size
;
889 if (len
!= sector_size
)
890 memset(dst
, 0, sector_size
);
891 memcpy(dst
, src
, len
);
893 /* note that its finished for this extent */
894 eccline
->bufs
[eccsect
] = NULL
;
895 nestiobuf_done(buf
, len
, 0);
902 udf_puteccline(eccline
);
907 /* sequential writing */
908 KASSERT(queue
== UDF_SHED_SEQWRITING
);
909 DPRINTF(SHEDULE
, ("\nudf_queuebuf_rmw SEQWRITE %p : sector XXXX "
910 "type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
911 buf
, buf
->b_udf_c_type
, buf
->b_resid
, buf
->b_bcount
,
914 * Buffers should not have been allocated to disc addresses yet on
915 * this queue. Note that a buffer can get multiple extents allocated.
916 * Note that it *looks* like the normal writing but its different in
919 * lmapping contains lb_num relative to base partition.
921 * XXX should we try to claim/organize the allocated memory to
922 * block-aligned pieces?
924 mutex_enter(&priv
->seqwrite_mutex
);
926 lmapping
= ump
->la_lmapping
;
927 node_ad_cpy
= ump
->la_node_ad_cpy
;
929 /* logically allocate buf and map it in the file */
930 udf_late_allocate_buf(ump
, buf
, lmapping
, node_ad_cpy
, &vpart_num
);
932 /* if we have FIDs, fixup using the new allocation table */
933 if (buf
->b_udf_c_type
== UDF_C_FIDS
) {
934 buf_len
= buf
->b_bcount
;
938 sectornr
= *lmappos
++;
939 len
= MIN(buf_len
, sector_size
);
940 fidblk
= (uint8_t *) buf
->b_data
+ bpos
;
941 udf_fixup_fid_block(fidblk
, sector_size
,
947 if (buf
->b_udf_c_type
== UDF_C_METADATA_SBM
) {
948 if (buf
->b_lblkno
== 0) {
949 /* update the tag location inside */
950 tag
= (struct desc_tag
*) buf
->b_data
;
951 tag
->tag_loc
= udf_rw32(*lmapping
);
952 udf_validate_tag_and_crc_sums(buf
->b_data
);
955 udf_fixup_node_internals(ump
, buf
->b_data
, buf
->b_udf_c_type
);
958 * Translate new mappings in lmapping to pmappings.
959 * pmapping to contain lb_nums as used for disc adressing.
961 pmapping
= ump
->la_pmapping
;
962 sectors
= (buf
->b_bcount
+ sector_size
-1) / sector_size
;
963 udf_translate_vtop_list(ump
, sectors
, vpart_num
, lmapping
, pmapping
);
965 /* copy parts into the bufs and set for writing */
967 buf_len
= buf
->b_bcount
;
968 sectornr
= *pmappos
++;
969 eccline
= udf_geteccline(ump
, sectornr
, ECC_SEQWRITING
);
970 eccsect
= sectornr
- eccline
->start_sector
;
973 len
= MIN(buf_len
, sector_size
);
974 eccsect
= sectornr
- eccline
->start_sector
;
975 if ((eccsect
< 0) || (eccsect
>= ump
->packet_size
)) {
976 eccline
->flags
|= ECC_SEQWRITING
;
977 udf_puteccline(eccline
);
978 eccline
= udf_geteccline(ump
, sectornr
, ECC_SEQWRITING
);
979 eccsect
= sectornr
- eccline
->start_sector
;
981 bit
= (uint64_t) 1 << eccsect
;
982 KASSERT((eccline
->readin
& bit
) == 0);
983 eccline
->present
|= bit
;
984 eccline
->dirty
|= bit
;
985 eccline
->bufs
[eccsect
] = NULL
;
987 src
= (uint8_t *) buf
->b_data
+ bpos
;
989 eccline
->blob
+ eccsect
* sector_size
;
990 if (len
!= sector_size
)
991 memset(dst
, 0, sector_size
);
992 memcpy(dst
, src
, len
);
994 /* note that its finished for this extent */
995 nestiobuf_done(buf
, len
, 0);
998 sectornr
= *pmappos
++;
1001 eccline
->flags
|= ECC_SEQWRITING
;
1002 udf_puteccline(eccline
);
1003 mutex_exit(&priv
->seqwrite_mutex
);
1006 /* --------------------------------------------------------------------- */
1009 udf_shedule_read_callback(struct buf
*buf
)
1011 struct udf_eccline
*eccline
= BTOE(buf
);
1012 struct udf_mount
*ump
= eccline
->ump
;
1015 int sector_size
= ump
->discinfo
.sector_size
;
1018 DPRINTF(ECCLINE
, ("read callback called on buf %p\n", buf
));
1020 /* post process read action */
1021 KASSERT(eccline
->flags
& ECC_LOCKED
);
1022 error
= buf
->b_error
;
1023 for (i
= 0; i
< ump
->packet_size
; i
++) {
1024 bit
= (uint64_t) 1 << i
;
1025 src
= (uint8_t *) buf
->b_data
+ i
* sector_size
;
1026 dst
= (uint8_t *) eccline
->blob
+ i
* sector_size
;
1027 if (eccline
->present
& bit
)
1029 eccline
->present
|= bit
;
1031 eccline
->error
|= bit
;
1032 if (eccline
->bufs
[i
]) {
1033 dst
= (uint8_t *) eccline
->bufs
[i
]->b_data
+
1034 eccline
->bufs_bpos
[i
];
1035 len
= eccline
->bufs_len
[i
];
1037 memcpy(dst
, src
, len
);
1038 nestiobuf_done(eccline
->bufs
[i
], len
, error
);
1039 eccline
->bufs
[i
] = NULL
;
1043 KASSERT(buf
->b_data
== eccline
->blob
);
1044 KASSERT(eccline
->present
== ((uint64_t) 1 << ump
->packet_size
)-1);
1047 * XXX TODO what to do on read errors? read in all sectors
1048 * synchronously and allocate a sparable entry?
1051 udf_puteccline(eccline
);
1052 DPRINTF(ECCLINE
, ("read callback finished\n"));
1057 udf_shedule_write_callback(struct buf
*buf
)
1059 struct udf_eccline
*eccline
= BTOE(buf
);
1060 struct udf_mount
*ump
= eccline
->ump
;
1064 DPRINTF(ECCLINE
, ("write callback called on buf %p\n", buf
));
1066 /* post process write action */
1067 KASSERT(eccline
->flags
& ECC_LOCKED
);
1068 error
= buf
->b_error
;
1069 for (i
= 0; i
< ump
->packet_size
; i
++) {
1070 bit
= (uint64_t) 1 << i
;
1071 if ((eccline
->dirty
& bit
) == 0)
1074 eccline
->error
|= bit
;
1076 eccline
->dirty
&= ~bit
;
1079 KASSERT(eccline
->bufs
[i
] == 0);
1081 KASSERT(eccline
->dirty
== 0);
1082 KASSERT(error
== 0);
1085 * XXX TODO on write errors allocate a sparable entry and reissue
1088 udf_puteccline(eccline
);
1089 DPRINTF(ECCLINE
, ("write callback finished\n"));
1094 udf_issue_eccline(struct udf_eccline
*eccline
, int queued_on
)
1096 struct udf_mount
*ump
= eccline
->ump
;
1097 struct strat_private
*priv
= PRIV(ump
);
1098 struct buf
*buf
, *nestbuf
;
1099 uint64_t bit
, allbits
= ((uint64_t) 1 << ump
->packet_size
)-1;
1101 int sector_size
= ump
->discinfo
.sector_size
;
1102 int blks
= sector_size
/ DEV_BSIZE
;
1105 KASSERT(eccline
->flags
& ECC_LOCKED
);
1107 if (queued_on
== UDF_SHED_READING
) {
1108 DPRINTF(SHEDULE
, ("udf_issue_eccline reading : "));
1109 /* read all bits that are not yet present */
1110 eccline
->readin
= (~eccline
->present
) & allbits
;
1111 KASSERT(eccline
->readin
);
1112 start
= eccline
->start_sector
;
1114 buf
->b_flags
= B_READ
| B_ASYNC
;
1115 SET(buf
->b_cflags
, BC_BUSY
); /* mark buffer busy */
1117 buf
->b_iodone
= udf_shedule_read_callback
;
1118 buf
->b_data
= eccline
->blob
;
1119 buf
->b_bcount
= ump
->packet_size
* sector_size
;
1120 buf
->b_resid
= buf
->b_bcount
;
1121 buf
->b_bufsize
= buf
->b_bcount
;
1122 buf
->b_private
= eccline
;
1123 BIO_SETPRIO(buf
, BPRIO_DEFAULT
);
1124 buf
->b_lblkno
= buf
->b_blkno
= buf
->b_rawblkno
= start
* blks
;
1127 if (eccline
->present
!= 0) {
1128 for (i
= 0; i
< ump
->packet_size
; i
++) {
1129 bit
= (uint64_t) 1 << i
;
1130 if (eccline
->present
& bit
) {
1131 nestiobuf_done(buf
, sector_size
, 0);
1134 nestbuf
= getiobuf(NULL
, true);
1135 nestiobuf_setup(buf
, nestbuf
, i
* sector_size
,
1137 /* adjust blocknumber to read */
1138 nestbuf
->b_blkno
= buf
->b_blkno
+ i
*blks
;
1139 nestbuf
->b_rawblkno
= buf
->b_rawblkno
+ i
*blks
;
1141 DPRINTF(SHEDULE
, ("sector %d ", start
+ i
));
1143 /* mutex dance since it could lock */
1144 mutex_exit(&priv
->discstrat_mutex
);
1145 /* call asynchronous */
1146 VOP_STRATEGY(ump
->devvp
, nestbuf
);
1147 mutex_enter(&priv
->discstrat_mutex
);
1149 DPRINTF(SHEDULE
, ("\n"));
1153 /* write or seqwrite */
1154 DPRINTF(SHEDULE
, ("udf_issue_eccline writing or seqwriting : "));
1155 DPRINTF(SHEDULE
, ("\n\tpresent %"PRIx64
", readin %"PRIx64
", "
1156 "dirty %"PRIx64
"\n\t", eccline
->present
, eccline
->readin
,
1158 KASSERT(eccline
->present
== allbits
);
1160 start
= eccline
->start_sector
;
1162 buf
->b_flags
= B_WRITE
| B_ASYNC
;
1163 SET(buf
->b_cflags
, BC_BUSY
); /* mark buffer busy */
1165 buf
->b_iodone
= udf_shedule_write_callback
;
1166 buf
->b_data
= eccline
->blob
;
1167 buf
->b_bcount
= ump
->packet_size
* sector_size
;
1168 buf
->b_resid
= buf
->b_bcount
;
1169 buf
->b_bufsize
= buf
->b_bcount
;
1170 buf
->b_private
= eccline
;
1171 BIO_SETPRIO(buf
, BPRIO_DEFAULT
);
1172 buf
->b_lblkno
= buf
->b_blkno
= buf
->b_rawblkno
= start
* blks
;
1176 /* mutex dance since it could lock */
1177 mutex_exit(&priv
->discstrat_mutex
);
1178 /* call asynchronous */
1179 DPRINTF(SHEDULE
, ("sector %d for %d\n",
1180 start
, ump
->packet_size
));
1181 VOP_STRATEGY(ump
->devvp
, buf
);
1182 mutex_enter(&priv
->discstrat_mutex
);
1187 udf_discstrat_thread(void *arg
)
1189 struct udf_mount
*ump
= (struct udf_mount
*) arg
;
1190 struct strat_private
*priv
= PRIV(ump
);
1191 struct udf_eccline
*eccline
;
1192 struct timespec now
, *last
;
1193 uint64_t allbits
= ((uint64_t) 1 << ump
->packet_size
)-1;
1194 int new_queue
, wait
, work
;
1197 priv
->thread_running
= 1;
1198 mutex_enter(&priv
->discstrat_mutex
);
1199 priv
->num_floating
= 0;
1200 while (priv
->run_thread
|| work
|| priv
->num_floating
) {
1202 vfs_timestamp(&now
);
1204 /* maintenance: handle eccline state machine */
1206 /* only peek at it */
1207 eccline
= udf_peek_eccline(priv
, UDF_SHED_WAITING
);
1208 if (eccline
== NULL
)
1211 /* if not reading, wait until the time has come */
1212 if ((priv
->cur_queue
!= UDF_SHED_READING
) &&
1213 (eccline
->wait_time
.tv_sec
- now
.tv_sec
> 0)) {
1214 UDF_UNLOCK_ECCLINE(eccline
);
1215 /* all others are later, so break off */
1220 UDF_UNLOCK_ECCLINE(eccline
);
1223 eccline
= udf_pop_eccline(priv
, UDF_SHED_WAITING
);
1225 /* requeue according to state */
1226 new_queue
= UDF_SHED_FREE
; /* unlikely */
1227 if (eccline
->refcnt
> 0)
1228 new_queue
= UDF_SHED_IDLE
;
1229 if (eccline
->flags
& ECC_WANTED
)
1230 new_queue
= UDF_SHED_IDLE
;
1231 if (eccline
->readin
)
1232 new_queue
= UDF_SHED_READING
;
1233 if (eccline
->dirty
) {
1234 new_queue
= UDF_SHED_READING
;
1235 if (eccline
->present
== allbits
) {
1236 new_queue
= UDF_SHED_WRITING
;
1237 if (eccline
->flags
& ECC_SEQWRITING
)
1238 new_queue
= UDF_SHED_SEQWRITING
;
1241 udf_push_eccline(eccline
, new_queue
);
1244 /* maintenance: free excess ecclines */
1245 while (priv
->num_queued
[UDF_SHED_FREE
] > UDF_ECCLINE_MAXFREE
) {
1246 eccline
= udf_pop_eccline(priv
, UDF_SHED_FREE
);
1248 KASSERT(eccline
->refcnt
== 0);
1249 if (eccline
->flags
& ECC_WANTED
) {
1250 /* we won the race, but we dont want to win */
1251 DPRINTF(ECCLINE
, ("Tried removing, pushed back to free list\n"));
1252 udf_push_eccline(eccline
, UDF_SHED_IDLE
);
1254 DPRINTF(ECCLINE
, ("Removing entry from free list\n"));
1255 udf_dispose_eccline(eccline
);
1259 /* process the current selected queue */
1261 vfs_timestamp(&now
);
1262 last
= &priv
->last_queued
[priv
->cur_queue
];
1265 eccline
= udf_pop_eccline(priv
, priv
->cur_queue
);
1268 new_queue
= priv
->cur_queue
;
1269 DPRINTF(ECCLINE
, ("UDF_ISSUE_ECCLINE\n"));
1271 udf_issue_eccline(eccline
, priv
->cur_queue
);
1273 /* don't switch too quickly */
1274 if (now
.tv_sec
- last
->tv_sec
< 2) {
1275 /* wait some time */
1276 cv_timedwait(&priv
->discstrat_cv
,
1277 &priv
->discstrat_mutex
, hz
);
1278 /* we assume there is work to be done */
1283 /* XXX select on queue lengths ? */
1285 /* check if we can/should switch */
1286 new_queue
= priv
->cur_queue
;
1287 if (bufq_peek(priv
->queues
[UDF_SHED_READING
]))
1288 new_queue
= UDF_SHED_READING
;
1289 if (bufq_peek(priv
->queues
[UDF_SHED_WRITING
]))
1290 new_queue
= UDF_SHED_WRITING
;
1291 if (bufq_peek(priv
->queues
[UDF_SHED_SEQWRITING
]))
1292 new_queue
= UDF_SHED_SEQWRITING
;
1296 mutex_exit(&priv
->discstrat_mutex
);
1298 if (new_queue
!= priv
->cur_queue
) {
1300 DPRINTF(SHEDULE
, ("switching from %d to %d\n",
1301 priv
->cur_queue
, new_queue
));
1302 priv
->cur_queue
= new_queue
;
1304 mutex_enter(&priv
->discstrat_mutex
);
1306 /* wait for more if needed */
1308 cv_timedwait(&priv
->discstrat_cv
,
1309 &priv
->discstrat_mutex
, hz
/4); /* /8 */
1311 work
= (bufq_peek(priv
->queues
[UDF_SHED_WAITING
]) != NULL
);
1312 work
|= (bufq_peek(priv
->queues
[UDF_SHED_READING
]) != NULL
);
1313 work
|= (bufq_peek(priv
->queues
[UDF_SHED_WRITING
]) != NULL
);
1314 work
|= (bufq_peek(priv
->queues
[UDF_SHED_SEQWRITING
]) != NULL
);
1316 DPRINTF(PARANOIA
, ("work : (%d, %d, %d) -> work %d, float %d\n",
1317 (bufq_peek(priv
->queues
[UDF_SHED_READING
]) != NULL
),
1318 (bufq_peek(priv
->queues
[UDF_SHED_WRITING
]) != NULL
),
1319 (bufq_peek(priv
->queues
[UDF_SHED_SEQWRITING
]) != NULL
),
1320 work
, priv
->num_floating
));
1323 mutex_exit(&priv
->discstrat_mutex
);
1325 /* tear down remaining ecclines */
1326 mutex_enter(&priv
->discstrat_mutex
);
1327 KASSERT(bufq_peek(priv
->queues
[UDF_SHED_WAITING
]) == NULL
);
1328 KASSERT(bufq_peek(priv
->queues
[UDF_SHED_IDLE
]) == NULL
);
1329 KASSERT(bufq_peek(priv
->queues
[UDF_SHED_READING
]) == NULL
);
1330 KASSERT(bufq_peek(priv
->queues
[UDF_SHED_WRITING
]) == NULL
);
1331 KASSERT(bufq_peek(priv
->queues
[UDF_SHED_SEQWRITING
]) == NULL
);
1333 KASSERT(priv
->num_queued
[UDF_SHED_WAITING
] == 0);
1334 KASSERT(priv
->num_queued
[UDF_SHED_IDLE
] == 0);
1335 KASSERT(priv
->num_queued
[UDF_SHED_READING
] == 0);
1336 KASSERT(priv
->num_queued
[UDF_SHED_WRITING
] == 0);
1337 KASSERT(priv
->num_queued
[UDF_SHED_SEQWRITING
] == 0);
1339 eccline
= udf_pop_eccline(priv
, UDF_SHED_FREE
);
1341 udf_dispose_eccline(eccline
);
1342 eccline
= udf_pop_eccline(priv
, UDF_SHED_FREE
);
1344 KASSERT(priv
->num_queued
[UDF_SHED_FREE
] == 0);
1345 mutex_exit(&priv
->discstrat_mutex
);
1347 priv
->thread_running
= 0;
1348 priv
->thread_finished
= 1;
1349 wakeup(&priv
->run_thread
);
1354 /* --------------------------------------------------------------------- */
1357 * Buffer memory pool allocator.
1361 ecclinepool_page_alloc(struct pool
*pp
, int flags
)
1363 return (void *)uvm_km_alloc(kernel_map
,
1365 ((flags
& PR_WAITOK
) ? 0 : UVM_KMF_NOWAIT
| UVM_KMF_TRYLOCK
)
1366 | UVM_KMF_WIRED
/* UVM_KMF_PAGABLE? */);
1370 ecclinepool_page_free(struct pool
*pp
, void *v
)
1372 uvm_km_free(kernel_map
, (vaddr_t
)v
, MAXBSIZE
, UVM_KMF_WIRED
);
1375 static struct pool_allocator ecclinepool_allocator
= {
1376 .pa_alloc
= ecclinepool_page_alloc
,
1377 .pa_free
= ecclinepool_page_free
,
1378 .pa_pagesz
= MAXBSIZE
,
1383 udf_discstrat_init_rmw(struct udf_strat_args
*args
)
1385 struct udf_mount
*ump
= args
->ump
;
1386 struct strat_private
*priv
= PRIV(ump
);
1387 uint32_t lb_size
, blobsize
, hashline
;
1391 KASSERT(ump
->logical_vol
);
1392 KASSERT(priv
== NULL
);
1394 lb_size
= udf_rw32(ump
->logical_vol
->lb_size
);
1395 blobsize
= ump
->packet_size
* lb_size
;
1396 KASSERT(lb_size
> 0);
1397 KASSERT(ump
->packet_size
<= 64);
1399 /* initialise our memory space */
1400 ump
->strategy_private
= malloc(sizeof(struct strat_private
),
1401 M_UDFTEMP
, M_WAITOK
);
1402 priv
= ump
->strategy_private
;
1403 memset(priv
, 0 , sizeof(struct strat_private
));
1405 /* initialise locks */
1406 cv_init(&priv
->discstrat_cv
, "udfstrat");
1407 mutex_init(&priv
->discstrat_mutex
, MUTEX_DEFAULT
, IPL_NONE
);
1408 mutex_init(&priv
->seqwrite_mutex
, MUTEX_DEFAULT
, IPL_NONE
);
1410 /* initialise struct eccline pool */
1411 pool_init(&priv
->eccline_pool
, sizeof(struct udf_eccline
),
1412 0, 0, 0, "udf_eccline_pool", NULL
, IPL_NONE
);
1414 /* initialise eccline blob pool */
1415 ecclinepool_allocator
.pa_pagesz
= blobsize
;
1416 pool_init(&priv
->ecclineblob_pool
, blobsize
,
1417 0, 0, 0, "udf_eccline_blob", &ecclinepool_allocator
, IPL_NONE
);
1419 /* initialise main queues */
1420 for (i
= 0; i
< UDF_SHED_MAX
; i
++) {
1421 priv
->num_queued
[i
] = 0;
1422 vfs_timestamp(&priv
->last_queued
[i
]);
1424 bufq_alloc(&priv
->queues
[UDF_SHED_WAITING
], "fcfs",
1425 BUFQ_SORT_RAWBLOCK
);
1426 bufq_alloc(&priv
->queues
[UDF_SHED_READING
], "disksort",
1427 BUFQ_SORT_RAWBLOCK
);
1428 bufq_alloc(&priv
->queues
[UDF_SHED_WRITING
], "disksort",
1429 BUFQ_SORT_RAWBLOCK
);
1430 bufq_alloc(&priv
->queues
[UDF_SHED_SEQWRITING
], "disksort", 0);
1432 /* initialise administrative queues */
1433 bufq_alloc(&priv
->queues
[UDF_SHED_IDLE
], "fcfs", 0);
1434 bufq_alloc(&priv
->queues
[UDF_SHED_FREE
], "fcfs", 0);
1436 for (hashline
= 0; hashline
< UDF_ECCBUF_HASHSIZE
; hashline
++) {
1437 LIST_INIT(&priv
->eccline_hash
[hashline
]);
1440 /* create our disk strategy thread */
1441 priv
->cur_queue
= UDF_SHED_READING
;
1442 priv
->thread_finished
= 0;
1443 priv
->thread_running
= 0;
1444 priv
->run_thread
= 1;
1445 if (kthread_create(PRI_NONE
, 0 /* KTHREAD_MPSAFE*/, NULL
/* cpu_info*/,
1446 udf_discstrat_thread
, ump
, &priv
->queue_lwp
,
1448 panic("fork udf_rw");
1451 /* wait for thread to spin up */
1452 while (!priv
->thread_running
) {
1453 tsleep(&priv
->thread_running
, PRIBIO
+1, "udfshedstart", hz
);
1459 udf_discstrat_finish_rmw(struct udf_strat_args
*args
)
1461 struct udf_mount
*ump
= args
->ump
;
1462 struct strat_private
*priv
= PRIV(ump
);
1467 /* stop our sheduling thread */
1468 KASSERT(priv
->run_thread
== 1);
1469 priv
->run_thread
= 0;
1470 wakeup(priv
->queue_lwp
);
1471 while (!priv
->thread_finished
) {
1472 tsleep(&priv
->run_thread
, PRIBIO
+ 1, "udfshedfin", hz
);
1474 /* kthread should be finished now */
1476 /* cleanup our pools */
1477 pool_destroy(&priv
->eccline_pool
);
1478 pool_destroy(&priv
->ecclineblob_pool
);
1480 cv_destroy(&priv
->discstrat_cv
);
1481 mutex_destroy(&priv
->discstrat_mutex
);
1482 mutex_destroy(&priv
->seqwrite_mutex
);
1484 /* free our private space */
1485 free(ump
->strategy_private
, M_UDFTEMP
);
1486 ump
->strategy_private
= NULL
;
1489 /* --------------------------------------------------------------------- */
1491 struct udf_strategy udf_strat_rmw
=
1493 udf_create_nodedscr_rmw
,
1494 udf_free_nodedscr_rmw
,
1495 udf_read_nodedscr_rmw
,
1496 udf_write_nodedscr_rmw
,
1498 udf_discstrat_init_rmw
,
1499 udf_discstrat_finish_rmw