Module Name: src Committed By: reinoud Date: Wed Jun 24 17:09:14 UTC 2009
Modified Files: src/sys/fs/udf: udf.h udf_allocation.c udf_subr.c udf_subr.h udf_vfsops.c udf_vnops.c Log Message: Commit first stage of free-space accounting. It is estimating the underlimit of free blocks on the device and when free blocks are getting tight it tries to readjust/recalculate that value by syncing the FS. Second stage will be resizing the data/metadata partitions. To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.34 src/sys/fs/udf/udf.h cvs rdiff -u -r1.25 -r1.26 src/sys/fs/udf/udf_allocation.c cvs rdiff -u -r1.94 -r1.95 src/sys/fs/udf/udf_subr.c cvs rdiff -u -r1.14 -r1.15 src/sys/fs/udf/udf_subr.h cvs rdiff -u -r1.56 -r1.57 src/sys/fs/udf/udf_vfsops.c cvs rdiff -u -r1.45 -r1.46 src/sys/fs/udf/udf_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/udf/udf.h diff -u src/sys/fs/udf/udf.h:1.33 src/sys/fs/udf/udf.h:1.34 --- src/sys/fs/udf/udf.h:1.33 Tue Jun 23 20:13:37 2009 +++ src/sys/fs/udf/udf.h Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf.h,v 1.33 2009/06/23 20:13:37 reinoud Exp $ */ +/* $NetBSD: udf.h,v 1.34 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -124,6 +124,7 @@ #define UDF_VAT_CHUNKSIZE (64*1024) /* picked */ #define UDF_SYMLINKBUFLEN (64*1024) /* picked */ +#define UDF_DISC_SLACK (128) /* picked, at least 64 kb or 128 */ #define UDF_ISO_VRS_SIZE (32*2048) /* 32 ISO `sectors' */ @@ -340,7 +341,7 @@ kcondvar_t dirtynodes_cv; /* sleeping on sync */ /* late allocation */ - uint32_t uncomitted_lb; /* for free space */ + int32_t uncommitted_lbs[UDF_PARTITIONS]; struct long_ad *la_node_ad_cpy; /* issue buf */ uint64_t *la_lmapping, *la_pmapping; /* issue buf */ @@ -387,6 +388,7 @@ struct lockf *lockf; /* lock list */ uint32_t outstanding_bufs; /* file data */ uint32_t outstanding_nodedscr; /* node dscr */ + int32_t uncommitted_lbs; /* in UBC */ /* references to associated nodes */ struct udf_node *extattr; Index: src/sys/fs/udf/udf_allocation.c diff -u src/sys/fs/udf/udf_allocation.c:1.25 src/sys/fs/udf/udf_allocation.c:1.26 --- src/sys/fs/udf/udf_allocation.c:1.25 Thu Jun 18 15:09:18 2009 +++ src/sys/fs/udf/udf_allocation.c Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_allocation.c,v 1.25 2009/06/18 15:09:18 reinoud Exp $ */ +/* $NetBSD: udf_allocation.c,v 1.26 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -28,7 +28,7 @@ #include <sys/cdefs.h> #ifndef lint -__KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.25 2009/06/18 15:09:18 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.26 2009/06/24 17:09:13 reinoud Exp $"); #endif /* not lint */ @@ -367,6 +367,93 @@ /* --------------------------------------------------------------------- */ +void +udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks) +{ + struct logvol_int_desc *lvid; + uint32_t *pos1, *pos2; + int vpart, num_vpart; + + lvid = ump->logvol_integrity; + *freeblks = *sizeblks = 0; + + /* + * Sequentials media report free space directly (CD/DVD/BD-R), for the + * other media we need the logical volume integrity. + * + * We sum all free space up here regardless of type. + */ + + KASSERT(lvid); + num_vpart = udf_rw32(lvid->num_part); + + if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { + /* use track info directly summing if there are 2 open */ + /* XXX assumption at most two tracks open */ + *freeblks = ump->data_track.free_blocks; + if (ump->data_track.tracknr != ump->metadata_track.tracknr) + *freeblks += ump->metadata_track.free_blocks; + *sizeblks = ump->discinfo.last_possible_lba; + } else { + /* free and used space for mountpoint based on logvol integrity */ + for (vpart = 0; vpart < num_vpart; vpart++) { + pos1 = &lvid->tables[0] + vpart; + pos2 = &lvid->tables[0] + num_vpart + vpart; + if (udf_rw32(*pos1) != (uint32_t) -1) { + *freeblks += udf_rw32(*pos1); + *sizeblks += udf_rw32(*pos2); + } + } + } + /* adjust for accounted uncommitted blocks */ + for (vpart = 0; vpart < num_vpart; vpart++) + *freeblks -= ump->uncommitted_lbs[vpart]; + + if (*freeblks > UDF_DISC_SLACK) { + *freeblks -= UDF_DISC_SLACK; + } else { + *freeblks = 0; + } +} + + +static void +udf_calc_vpart_freespace(struct udf_mount *ump, uint16_t vpart_num, uint64_t *freeblks) +{ + struct logvol_int_desc *lvid; + uint32_t *pos1; + + lvid = ump->logvol_integrity; + *freeblks = 0; + + /* + * Sequentials media report free space directly (CD/DVD/BD-R), for the + * other media we need the logical volume integrity. + * + * We sum all free space up here regardless of type. + */ + + KASSERT(lvid); + if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { + /* XXX assumption at most two tracks open */ + if (vpart_num == ump->data_part) { + *freeblks = ump->data_track.free_blocks; + } else { + *freeblks = ump->metadata_track.free_blocks; + } + } else { + /* free and used space for mountpoint based on logvol integrity */ + pos1 = &lvid->tables[0] + vpart_num; + if (udf_rw32(*pos1) != (uint32_t) -1) + *freeblks += udf_rw32(*pos1); + } + + /* adjust for accounted uncommitted blocks */ + *freeblks -= ump->uncommitted_lbs[vpart_num]; +} + +/* --------------------------------------------------------------------- */ + int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, uint32_t *lb_numres, uint32_t *extres) @@ -897,11 +984,139 @@ } } +/* --------------------------------------------------------------------- */ -/* allocate a contiguous sequence of sectornumbers */ -static int -udf_allocate_space(struct udf_mount *ump, int udf_c_type, - uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping) +/* + * We check for overall disc space with a margin to prevent critical + * conditions. If disc space is low we try to force a sync() to improve our + * estimates. When confronted with meta-data partition size shortage we know + * we have to check if it can be extended and we need to extend it when + * needed. + * + * A 2nd strategy we could use when disc space is getting low on a disc + * formatted with a meta-data partition is to see if there are sparse areas in + * the meta-data partition and free blocks there for extra data. + */ + +void +udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, + uint16_t vpart_num, uint32_t num_lb) +{ + ump->uncommitted_lbs[vpart_num] += num_lb; + if (udf_node) + udf_node->uncommitted_lbs += num_lb; +} + + +void +udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node, + uint16_t vpart_num, uint32_t num_lb) +{ + ump->uncommitted_lbs[vpart_num] -= num_lb; + if (ump->uncommitted_lbs[vpart_num] < 0) { + DPRINTF(RESERVE, ("UDF: underflow on partition reservation, " + "part %d: %d\n", vpart_num, + ump->uncommitted_lbs[vpart_num])); + ump->uncommitted_lbs[vpart_num] = 0; + } + if (udf_node) { + udf_node->uncommitted_lbs -= num_lb; + if (udf_node->uncommitted_lbs < 0) { + DPRINTF(RESERVE, ("UDF: underflow of node " + "reservation : %d\n", + udf_node->uncommitted_lbs)); + udf_node->uncommitted_lbs = 0; + } + } +} + + +int +udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, + int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail) +{ + uint64_t freeblks; + uint64_t slack; + int i, error; + + slack = 0; + if (can_fail) + slack = UDF_DISC_SLACK; + + error = 0; + mutex_enter(&ump->allocate_mutex); + + /* check if there is enough space available */ + for (i = 0; i < 16; i++) { /* XXX arbitrary number */ + udf_calc_vpart_freespace(ump, vpart_num, &freeblks); + if (num_lb + slack < freeblks) + break; + /* issue SYNC */ + DPRINTF(RESERVE, ("udf_reserve_space: issuing sync\n")); + mutex_exit(&ump->allocate_mutex); + udf_do_sync(ump, FSCRED, 0); + mutex_enter(&mntvnode_lock); + /* 1/4 second wait */ + cv_timedwait(&ump->dirtynodes_cv, &mntvnode_lock, + hz/4); + mutex_exit(&mntvnode_lock); + mutex_enter(&ump->allocate_mutex); + } + + /* check if there is enough space available now */ + udf_calc_vpart_freespace(ump, vpart_num, &freeblks); + if (num_lb + slack >= freeblks) { + DPRINTF(RESERVE, ("udf_reserve_space: try to juggle partitions\n")); + /* TODO juggle with data and metadata partitions if possible */ + } + + /* check if there is enough space available now */ + udf_calc_vpart_freespace(ump, vpart_num, &freeblks); + if (num_lb + slack <= freeblks) { + udf_do_reserve_space(ump, udf_node, vpart_num, num_lb); + } else { + DPRINTF(RESERVE, ("udf_reserve_space: out of disc space\n")); + error = ENOSPC; + } + + mutex_exit(&ump->allocate_mutex); + return error; +} + + +void +udf_cleanup_reservation(struct udf_node *udf_node) +{ + struct udf_mount *ump = udf_node->ump; + int vpart_num; + + mutex_enter(&ump->allocate_mutex); + + /* compensate for overlapping blocks */ + DPRINTF(RESERVE, ("UDF: overlapped %d blocks in count\n", udf_node->uncommitted_lbs)); + + vpart_num = udf_get_record_vpart(ump, udf_get_c_type(udf_node)); + udf_do_unreserve_space(ump, udf_node, vpart_num, udf_node->uncommitted_lbs); + + DPRINTF(RESERVE, ("\ttotal now %d\n", ump->uncommitted_lbs[vpart_num])); + + /* sanity */ + if (ump->uncommitted_lbs[vpart_num] < 0) + ump->uncommitted_lbs[vpart_num] = 0; + + mutex_exit(&ump->allocate_mutex); +} + +/* --------------------------------------------------------------------- */ + +/* + * Allocate an extent of given length on given virt. partition. It doesn't + * have to be one stretch. + */ + +int +udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node, + int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping) { struct mmc_trackinfo *alloc_track, *other_track; struct udf_bitmap *bitmap; @@ -920,8 +1135,6 @@ lb_size = udf_rw32(ump->logical_vol->lb_size); KASSERT(lb_size == ump->discinfo.sector_size); - /* XXX TODO check disc space */ - alloc_type = ump->vtop_alloc[vpart_num]; is_node = (udf_c_type == UDF_C_NODE); @@ -932,8 +1145,14 @@ /* search empty slot in VAT file */ KASSERT(num_lb == 1); error = udf_search_free_vatloc(ump, &lb_num); - if (!error) + if (!error) { *lmappos = lb_num; + + /* reserve on the backing sequential partition since + * that partition is credited back later */ + udf_do_reserve_space(ump, udf_node, + ump->vtop[vpart_num], num_lb); + } break; case UDF_ALLOC_SEQUENTIAL : /* sequential allocation on recordable media */ @@ -1023,6 +1242,11 @@ break; } + if (!error) { + /* credit our partition since we have committed the space */ + udf_do_unreserve_space(ump, udf_node, vpart_num, num_lb); + } + #ifdef DEBUG if (udf_verbose & UDF_DEBUG_ALLOC) { lmappos = lmapping; @@ -1131,24 +1355,6 @@ /* --------------------------------------------------------------------- */ -int -udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, - uint32_t num_lb, uint16_t vpartnr, uint64_t *lmapping) -{ - /* TODO properly maintain uncomitted_lb per partition */ - - /* reserve size for VAT allocated data */ - if (ump->vtop_alloc[vpartnr] == UDF_ALLOC_VAT) { - mutex_enter(&ump->allocate_mutex); - ump->uncomitted_lb += num_lb; - mutex_exit(&ump->allocate_mutex); - } - - return udf_allocate_space(ump, udf_c_type, vpartnr, num_lb, lmapping); -} - -/* --------------------------------------------------------------------- */ - /* * Allocate a buf on disc for direct write out. The space doesn't have to be * contiguous as the caller takes care of this. @@ -1178,12 +1384,7 @@ KASSERT(lb_size == ump->discinfo.sector_size); /* select partition to record the buffer on */ - vpart_num = ump->data_part; - if (udf_c_type == UDF_C_NODE) - vpart_num = ump->node_part; - if (udf_c_type == UDF_C_FIDS) - vpart_num = ump->fids_part; - *vpart_nump = vpart_num; + vpart_num = *vpart_nump = udf_get_record_vpart(ump, udf_c_type); if (udf_c_type == UDF_C_NODE) { /* if not VAT, its allready allocated */ @@ -1194,23 +1395,18 @@ vpart_num = ump->data_part; } + /* XXX can this still happen? */ /* do allocation on the selected partition */ - error = udf_allocate_space(ump, udf_c_type, + error = udf_allocate_space(ump, udf_node, udf_c_type, vpart_num, num_lb, lmapping); if (error) { - /* ARGH! we've not done our accounting right! */ + /* + * ARGH! we haven't done our accounting right! it should + * allways succeed. + */ panic("UDF disc allocation accounting gone wrong"); } - /* commit our sector count */ - mutex_enter(&ump->allocate_mutex); - if (num_lb > ump->uncomitted_lb) { - ump->uncomitted_lb = 0; - } else { - ump->uncomitted_lb -= num_lb; - } - mutex_exit(&ump->allocate_mutex); - /* If its userdata or FIDs, record its allocation in its node. */ if ((udf_c_type == UDF_C_USERDATA) || (udf_c_type == UDF_C_FIDS) || @@ -1607,11 +1803,17 @@ if (ext == NULL) { DPRINTF(ALLOC,("adding allocation extent %d\n", extnr)); - error = udf_pre_allocate_space(ump, UDF_C_NODE, 1, - vpart_num, &lmapping); + error = udf_reserve_space(ump, NULL, UDF_C_NODE, + vpart_num, 1, /* can fail */ false); + if (error) { + printf("UDF: couldn't reserve space for AED!\n"); + return error; + } + error = udf_allocate_space(ump, NULL, UDF_C_NODE, + vpart_num, 1, &lmapping); lb_num = lmapping; if (error) - return error; + panic("UDF: couldn't allocate AED!\n"); /* initialise pointer to location */ memset(&l_icb, 0, sizeof(struct long_ad)); @@ -2150,7 +2352,7 @@ uint8_t *data_pos, *evacuated_data; int addr_type; int slot, cpy_slot; - int isdir, eof, error; + int eof, error; DPRINTF(ALLOC, ("udf_grow_node\n")); @@ -2251,9 +2453,8 @@ } /* convert to a normal alloc and select type */ - isdir = (vp->v_type == VDIR); my_part = udf_rw16(udf_node->loc.loc.part_num); - dst_part = isdir ? ump->fids_part : ump->data_part; + dst_part = udf_get_record_vpart(ump, udf_get_c_type(udf_node)); addr_type = UDF_ICB_SHORT_ALLOC; if (dst_part != my_part) addr_type = UDF_ICB_LONG_ALLOC; Index: src/sys/fs/udf/udf_subr.c diff -u src/sys/fs/udf/udf_subr.c:1.94 src/sys/fs/udf/udf_subr.c:1.95 --- src/sys/fs/udf/udf_subr.c:1.94 Tue Jun 23 20:09:07 2009 +++ src/sys/fs/udf/udf_subr.c Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_subr.c,v 1.94 2009/06/23 20:09:07 reinoud Exp $ */ +/* $NetBSD: udf_subr.c,v 1.95 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -29,7 +29,7 @@ #include <sys/cdefs.h> #ifndef lint -__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.94 2009/06/23 20:09:07 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.95 2009/06/24 17:09:13 reinoud Exp $"); #endif /* not lint */ @@ -953,6 +953,38 @@ /* --------------------------------------------------------------------- */ +int +udf_get_c_type(struct udf_node *udf_node) +{ + int isdir, what; + + isdir = (udf_node->vnode->v_type == VDIR); + what = isdir ? UDF_C_FIDS : UDF_C_USERDATA; + + if (udf_node->ump) + if (udf_node == udf_node->ump->metadatabitmap_node) + what = UDF_C_METADATA_SBM; + + return what; +} + + +int +udf_get_record_vpart(struct udf_mount *ump, int udf_c_type) +{ + int vpart_num; + + vpart_num = ump->data_part; + if (udf_c_type == UDF_C_NODE) + vpart_num = ump->node_part; + if (udf_c_type == UDF_C_FIDS) + vpart_num = ump->fids_part; + + return vpart_num; +} + +/* --------------------------------------------------------------------- */ + /* we dont try to be smart; we just record the parts */ #define UDF_UPDATE_DSCR(name, dscr) \ if (name) \ @@ -2776,7 +2808,7 @@ DPRINTF(CALL, ("udf_writeout_vat\n")); - mutex_enter(&ump->allocate_mutex); +// mutex_enter(&ump->allocate_mutex); udf_update_vat_descriptor(ump); /* write out the VAT contents ; TODO intelligent writing */ @@ -2789,7 +2821,7 @@ goto out; } - mutex_exit(&ump->allocate_mutex); +// mutex_exit(&ump->allocate_mutex); vflushbuf(ump->vat_node->vnode, 1 /* sync */); error = VOP_FSYNC(ump->vat_node->vnode, @@ -3898,24 +3930,53 @@ */ /* - * Callback from genfs to allocate len bytes at offset off; only called when - * filling up gaps in the allocation. + * Called for allocating an extent of the file either by VOP_WRITE() or by + * genfs filling up gaps. */ -/* XXX should we check if there is space enough in udf_gop_alloc? */ static int udf_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, kauth_cred_t cred) { -#if 0 struct udf_node *udf_node = VTOI(vp); struct udf_mount *ump = udf_node->ump; + uint64_t lb_start, lb_end; uint32_t lb_size, num_lb; -#endif + int udf_c_type, vpart_num, can_fail; + int error; - DPRINTF(NOTIMPL, ("udf_gop_alloc not implemented\n")); - DPRINTF(ALLOC, ("udf_gop_alloc called for %"PRIu64" bytes\n", len)); + DPRINTF(ALLOC, ("udf_gop_alloc called for offset %"PRIu64" for %"PRIu64" bytes, %s\n", + off, len, flags? "SYNC":"NONE")); - return 0; + /* + * request the pages of our vnode and see how many pages will need to + * be allocated and reserve that space + */ + lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); + lb_start = off / lb_size; + lb_end = (off + len + lb_size -1) / lb_size; + num_lb = lb_end - lb_start; + + udf_c_type = udf_get_c_type(udf_node); + vpart_num = udf_get_record_vpart(ump, udf_c_type); + + /* all requests can fail */ + can_fail = true; + + /* fid's (directories) can't fail */ + if (udf_c_type == UDF_C_FIDS) + can_fail = false; + + /* system files can't fail */ + if (vp->v_vflag & VV_SYSTEM) + can_fail = false; + + error = udf_reserve_space(ump, udf_node, udf_c_type, + vpart_num, num_lb, can_fail); + + DPRINTF(ALLOC, ("\tlb_start %"PRIu64", lb_end %"PRIu64", num_lb %d\n", + lb_start, lb_end, num_lb)); + + return error; } @@ -5255,6 +5316,7 @@ genfs_node_init(nvp, &udf_genfsops); /* inititise genfs */ udf_node->outstanding_bufs = 0; udf_node->outstanding_nodedscr = 0; + udf_node->uncommitted_lbs = 0; /* check if we're fetching the root */ if (ump->fileset_desc) @@ -5548,12 +5610,16 @@ if (udf_node->i_flags & IN_DELETED) { DPRINTF(NODE, ("\tnode deleted; not writing out\n")); + udf_cleanup_reservation(udf_node); return 0; } /* lock node; unlocked in callback */ UDF_LOCK_NODE(udf_node, 0); + /* remove pending reservations, we're written out */ + udf_cleanup_reservation(udf_node); + /* at least one descriptor writeout */ udf_node->outstanding_nodedscr = 1; @@ -5587,6 +5653,7 @@ loc = &udf_node->write_loc; error = udf_write_logvol_dscr(udf_node, dscr, loc, waitfor); + return error; } @@ -5611,6 +5678,7 @@ "v_numoutput = %d", udf_node, vp->v_numoutput); #endif + udf_cleanup_reservation(udf_node); /* TODO extended attributes and streamdir */ @@ -5685,22 +5753,22 @@ /* lock node */ error = vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY); - if (error) { - nvp->v_data = NULL; - ungetnewvnode(nvp); - return error; - } + if (error) + goto error_out_unget; - /* get disc allocation for one logical block */ + /* reserve space for one logical block */ vpart_num = ump->node_part; - error = udf_pre_allocate_space(ump, UDF_C_NODE, 1, - vpart_num, &lmapping); + error = udf_reserve_space(ump, NULL, UDF_C_NODE, + vpart_num, 1, /* can_fail */ true); + if (error) + goto error_out_unlock; + + /* allocate node */ + error = udf_allocate_space(ump, NULL, UDF_C_NODE, + vpart_num, 1, &lmapping); + if (error) + goto error_out_unreserve; lb_num = lmapping; - if (error) { - vlockmgr(nvp->v_vnlock, LK_RELEASE); - ungetnewvnode(nvp); - return error; - } /* initialise pointer to location */ memset(&node_icb_loc, 0, sizeof(struct long_ad)); @@ -5724,6 +5792,7 @@ cv_init(&udf_node->node_lock, "udf_nlk"); udf_node->outstanding_bufs = 0; udf_node->outstanding_nodedscr = 0; + udf_node->uncommitted_lbs = 0; /* initialise genfs */ genfs_node_init(nvp, &udf_genfsops); @@ -5790,6 +5859,18 @@ *vpp = nvp; return 0; + +error_out_unreserve: + udf_do_unreserve_space(ump, NULL, vpart_num, 1); + +error_out_unlock: + vlockmgr(nvp->v_vnlock, LK_RELEASE); + +error_out_unget: + nvp->v_data = NULL; + ungetnewvnode(nvp); + + return error; } @@ -6470,15 +6551,14 @@ uint32_t from, lblkno; uint32_t sectors; uint8_t *buf_pos; - int error, run_length, isdir, what; + int error, run_length, what; sector_size = udf_node->ump->discinfo.sector_size; from = buf->b_blkno; sectors = buf->b_bcount / sector_size; - isdir = (udf_node->vnode->v_type == VDIR); - what = isdir ? UDF_C_FIDS : UDF_C_USERDATA; + what = udf_get_c_type(udf_node); /* assure we have enough translation slots */ KASSERT(buf->b_bcount / sector_size <= UDF_MAX_MAPPINGS); @@ -6599,18 +6679,14 @@ uint32_t buf_offset, lb_num, rbuflen, rblk; uint32_t from, lblkno; uint32_t num_lb; - int error, run_length, isdir, what, s; + int error, run_length, what, s; lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); from = buf->b_blkno; num_lb = buf->b_bcount / lb_size; - isdir = (udf_node->vnode->v_type == VDIR); - what = isdir ? UDF_C_FIDS : UDF_C_USERDATA; - - if (udf_node == ump->metadatabitmap_node) - what = UDF_C_METADATA_SBM; + what = udf_get_c_type(udf_node); /* assure we have enough translation slots */ KASSERT(buf->b_bcount / lb_size <= UDF_MAX_MAPPINGS); @@ -6659,7 +6735,6 @@ */ /* XXX why not ignore the mapping altogether ? */ - /* TODO estimate here how much will be late-allocated */ DPRINTF(WRITE, ("\twrite lb_num " "%"PRIu64, mapping[lb_num])); @@ -6679,19 +6754,6 @@ rbuflen = run_length * lb_size; rblk = run_start * (lb_size/DEV_BSIZE); -#if 0 - /* if its zero or unmapped, our blknr gets -1 for unmapped */ - switch (mapping[lb_num]) { - case UDF_TRANS_UNMAPPED: - case UDF_TRANS_ZERO: - rblk = -1; - break; - default: - rblk = run_start * (lb_size/DEV_BSIZE); - break; - } -#endif - nestbuf = getiobuf(NULL, true); nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen); /* nestbuf is B_ASYNC */ Index: src/sys/fs/udf/udf_subr.h diff -u src/sys/fs/udf/udf_subr.h:1.14 src/sys/fs/udf/udf_subr.h:1.15 --- src/sys/fs/udf/udf_subr.h:1.14 Tue Jun 23 20:09:07 2009 +++ src/sys/fs/udf/udf_subr.h Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_subr.h,v 1.14 2009/06/23 20:09:07 reinoud Exp $ */ +/* $NetBSD: udf_subr.h,v 1.15 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -109,11 +109,18 @@ int udf_vat_write(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset); /* disc allocation */ -void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_num); +int udf_get_c_type(struct udf_node *udf_node); +int udf_get_record_vpart(struct udf_mount *ump, int udf_c_type); +void udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb); +void udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb); +int udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail); +void udf_cleanup_reservation(struct udf_node *udf_node); +int udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping); void udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, uint16_t vpart_num, uint32_t num_lb); -int udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, uint32_t num_lb, uint16_t vpartnr, uint64_t *lmapping); +void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_num); int udf_grow_node(struct udf_node *node, uint64_t new_size); int udf_shrink_node(struct udf_node *node, uint64_t new_size); +void udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks); /* node readers and writers */ uint64_t udf_advance_uniqueid(struct udf_mount *ump); Index: src/sys/fs/udf/udf_vfsops.c diff -u src/sys/fs/udf/udf_vfsops.c:1.56 src/sys/fs/udf/udf_vfsops.c:1.57 --- src/sys/fs/udf/udf_vfsops.c:1.56 Sat Apr 25 18:53:45 2009 +++ src/sys/fs/udf/udf_vfsops.c Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_vfsops.c,v 1.56 2009/04/25 18:53:45 elad Exp $ */ +/* $NetBSD: udf_vfsops.c,v 1.57 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -28,7 +28,7 @@ #include <sys/cdefs.h> #ifndef lint -__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.56 2009/04/25 18:53:45 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.57 2009/06/24 17:09:13 reinoud Exp $"); #endif /* not lint */ @@ -782,8 +782,7 @@ struct logvol_int_desc *lvid; struct udf_logvol_info *impl; uint64_t freeblks, sizeblks; - uint32_t *pos1, *pos2; - int part, num_part; + int num_part; DPRINTF(CALL, ("udf_statvfs called\n")); sbp->f_flag = mp->mnt_flag; @@ -792,36 +791,16 @@ sbp->f_iosize = ump->discinfo.sector_size; mutex_enter(&ump->allocate_mutex); - lvid = ump->logvol_integrity; - freeblks = sizeblks = 0; - - /* Sequentials report free space directly (CD/DVD/BD-R) */ - KASSERT(lvid); - num_part = udf_rw32(lvid->num_part); - impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part); - if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { - /* XXX assumption at most two tracks open */ - freeblks = ump->data_track.free_blocks; - if (ump->data_track.tracknr != ump->metadata_track.tracknr) - freeblks += ump->metadata_track.free_blocks; - sizeblks = ump->discinfo.last_possible_lba; - } else { - /* free and used space for mountpoint based on logvol integrity */ - for (part=0; part < num_part; part++) { - pos1 = &lvid->tables[0] + part; - pos2 = &lvid->tables[0] + num_part + part; - if (udf_rw32(*pos1) != (uint32_t) -1) { - freeblks += udf_rw32(*pos1); - sizeblks += udf_rw32(*pos2); - } - } - } - freeblks -= ump->uncomitted_lb; + udf_calc_freespace(ump, &sizeblks, &freeblks); sbp->f_blocks = sizeblks; sbp->f_bfree = freeblks; sbp->f_files = 0; + + lvid = ump->logvol_integrity; + num_part = udf_rw32(lvid->num_part); + impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part); if (impl) { sbp->f_files = udf_rw32(impl->num_files); sbp->f_files += udf_rw32(impl->num_directories); Index: src/sys/fs/udf/udf_vnops.c diff -u src/sys/fs/udf/udf_vnops.c:1.45 src/sys/fs/udf/udf_vnops.c:1.46 --- src/sys/fs/udf/udf_vnops.c:1.45 Tue Jun 23 20:09:07 2009 +++ src/sys/fs/udf/udf_vnops.c Wed Jun 24 17:09:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: udf_vnops.c,v 1.45 2009/06/23 20:09:07 reinoud Exp $ */ +/* $NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $ */ /* * Copyright (c) 2006, 2008 Reinoud Zandijk @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.45 2009/06/23 20:09:07 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $"); #endif /* not lint */ @@ -277,6 +277,7 @@ uint64_t file_size, old_size, old_offset; vsize_t len; int async = vp->v_mount->mnt_flag & MNT_ASYNC; + int aflag = ioflag & IO_SYNC ? B_SYNC : 0; int error; int resid, extended; @@ -344,6 +345,12 @@ if (len == 0) break; + genfs_node_wrlock(vp); + error = GOP_ALLOC(vp, uio->uio_offset, len, aflag, cred); + genfs_node_unlock(vp); + if (error) + break; + /* ubc, here we come, prepare to trap */ error = ubc_uiomove(uobj, uio, len, advice, UBC_WRITE | UBC_UNMAP_FLAG(vp));