xref: /titanic_50/usr/src/uts/common/fs/udfs/udf_alloc.c (revision 33f5ff17089e3a43e6e730bf80384c233123dbd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/t_lock.h>
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/systm.h>
32 #include <sys/sysmacros.h>
33 #include <sys/resource.h>
34 #include <sys/signal.h>
35 #include <sys/cred.h>
36 #include <sys/user.h>
37 #include <sys/buf.h>
38 #include <sys/vfs.h>
39 #include <sys/stat.h>
40 #include <sys/vnode.h>
41 #include <sys/mode.h>
42 #include <sys/proc.h>
43 #include <sys/disp.h>
44 #include <sys/file.h>
45 #include <sys/fcntl.h>
46 #include <sys/flock.h>
47 #include <sys/kmem.h>
48 #include <sys/uio.h>
49 #include <sys/dnlc.h>
50 #include <sys/conf.h>
51 #include <sys/errno.h>
52 #include <sys/mman.h>
53 #include <sys/fbuf.h>
54 #include <sys/pathname.h>
55 #include <sys/debug.h>
56 #include <sys/vmsystm.h>
57 #include <sys/cmn_err.h>
58 #include <sys/dirent.h>
59 #include <sys/errno.h>
60 #include <sys/modctl.h>
61 #include <sys/statvfs.h>
62 #include <sys/mount.h>
63 #include <sys/sunddi.h>
64 #include <sys/bootconf.h>
65 #include <sys/policy.h>
66 
67 #include <vm/hat.h>
68 #include <vm/page.h>
69 #include <vm/pvn.h>
70 #include <vm/as.h>
71 #include <vm/seg.h>
72 #include <vm/seg_map.h>
73 #include <vm/seg_kmem.h>
74 #include <vm/seg_vn.h>
75 #include <vm/rm.h>
76 #include <vm/page.h>
77 #include <sys/swap.h>
78 
79 #include <fs/fs_subr.h>
80 
81 #include <sys/fs/udf_volume.h>
82 #include <sys/fs/udf_inode.h>
83 
84 #ifdef	DEBUG
85 extern struct ud_inode *ud_search_icache(struct vfs *, uint16_t, uint32_t);
86 #endif
87 
88 int32_t ud_alloc_space_bmap(struct vfs *, struct ud_part *,
89 	uint32_t, uint32_t, uint32_t *, uint32_t *, int32_t);
90 int32_t ud_check_free_and_mark_used(struct vfs *,
91 	struct ud_part *, uint32_t, uint32_t *);
92 int32_t ud_check_free(uint8_t *, uint8_t *, uint32_t, uint32_t);
93 void ud_mark_used(uint8_t *, uint32_t, uint32_t);
94 void ud_mark_free(uint8_t *, uint32_t, uint32_t);
95 int32_t ud_alloc_space_stbl(struct vfs *, struct ud_part *,
96 	uint32_t, uint32_t, uint32_t *, uint32_t *, int32_t);
97 int32_t ud_free_space_bmap(struct vfs *,
98 	struct ud_part *, uint32_t, uint32_t);
99 int32_t ud_free_space_stbl(struct vfs *,
100 	struct ud_part *, uint32_t, uint32_t);
101 
102 
103 /*
104  * WORKSAROUND to the buffer cache crap
105  * If the requested block exists in the buffer cache
106  * buffer cache does not care about the count
107  * it just returns the old buffer(does not even
108  * set resid value). Same problem exists if the
109  * block that is requested is not the first block
110  * in the cached buffer then this will return
111  * a different buffer. We work around the above by
112  * using a fixed size request to the buffer cache
113  * all the time. This is currently udf_lbsize.
114  * (Actually it is restricted to udf_lbsize
115  * because iget always does udf_lbsize requests)
116  */
117 
118 
119 /*
120  * allocate blkcount blocks continuously
121  * near "proximity" block in partion defined by prn.
122  * if proximity != 0 means less_is_ok = 0
123  * return the starting block no and count
124  * of blocks allocated in start_blkno & size
125  * if less_is_ok == 0 then allocate only if
126  * entire requirement can be met.
127  */
128 int32_t
129 ud_alloc_space(struct vfs *vfsp, uint16_t prn,
130 	uint32_t proximity, uint32_t blkcount,
131 	uint32_t *start_blkno, uint32_t *size,
132 	int32_t less_is_ok, int32_t metadata)
133 {
134 	int32_t i, error = 0;
135 	struct udf_vfs *udf_vfsp;
136 	struct ud_part *ud_part;
137 
138 	ud_printf("ud_alloc_space\n");
139 
140 
141 /*
142  * prom_printf("ud_alloc_space %x %x %x %x\n",
143  * proximity, blkcount, less_is_ok, metadata);
144  */
145 
146 	if (blkcount == 0) {
147 		*start_blkno = 0;
148 		*size = 0;
149 		return (0);
150 	}
151 
152 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
153 	ud_part = udf_vfsp->udf_parts;
154 	for (i = 0; i < udf_vfsp->udf_npart; i++) {
155 		if (prn == ud_part->udp_number) {
156 			break;
157 		}
158 		ud_part ++;
159 	}
160 
161 	if (i == udf_vfsp->udf_npart) {
162 		return (1);
163 	}
164 	*start_blkno = 0;
165 	*size = 0;
166 	if (metadata) {
167 		error = ud_alloc_from_cache(udf_vfsp, ud_part, start_blkno);
168 		if (error == 0) {
169 			*size = 1;
170 			return (0);
171 		}
172 	}
173 	if (ud_part->udp_nfree != 0) {
174 		if (ud_part->udp_flags == UDP_BITMAPS) {
175 			error = ud_alloc_space_bmap(vfsp, ud_part, proximity,
176 			    blkcount, start_blkno, size, less_is_ok);
177 		} else {
178 			error = ud_alloc_space_stbl(vfsp, ud_part, proximity,
179 			    blkcount, start_blkno, size, less_is_ok);
180 		}
181 		if (error == 0) {
182 			mutex_enter(&udf_vfsp->udf_lock);
183 			ASSERT(ud_part->udp_nfree >= *size);
184 			ASSERT(udf_vfsp->udf_freeblks >= *size);
185 			ud_part->udp_nfree -= *size;
186 			udf_vfsp->udf_freeblks -= *size;
187 			mutex_exit(&udf_vfsp->udf_lock);
188 		}
189 	} else {
190 		error = ENOSPC;
191 	}
192 /*
193  * prom_printf("end %x %x %x\n", error, *start_blkno, *size);
194  */
195 
196 	return (error);
197 }
198 
199 #ifdef	SKIP_USED_BLOCKS
200 /*
201  * This table is manually constructed
202  */
203 int8_t skip[256] = {
204 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
205 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
206 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
207 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
208 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
209 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
210 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
211 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
212 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
213 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
214 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
215 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
216 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
217 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
218 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
219 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
220 };
221 #endif
222 
223 #define	HDR_BLKS	(24 * 8)
224 
225 int32_t
226 ud_alloc_space_bmap(struct vfs *vfsp,
227 	struct ud_part *ud_part, uint32_t proximity,
228 	uint32_t blkcount, uint32_t *start_blkno,
229 	uint32_t *size, int32_t less_is_ok)
230 {
231 	struct buf *bp = NULL;
232 	struct udf_vfs *udf_vfsp;
233 	uint32_t old_loc, old_size, new_size;
234 	uint8_t *addr, *eaddr;
235 	uint32_t loop_count, loop_begin, loop_end;
236 	uint32_t bno, begin, dummy, temp, lbsz, bb_count;
237 	uint32_t bblk = 0, eblk = 0;
238 	int32_t fragmented;
239 
240 	ud_printf("ud_alloc_space_bmap\n");
241 
242 	ASSERT(ud_part);
243 	ASSERT(ud_part->udp_flags == UDP_BITMAPS);
244 
245 	if (ud_part->udp_unall_len == 0) {
246 		return (ENOSPC);
247 	}
248 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
249 	lbsz = udf_vfsp->udf_lbsize;
250 	bb_count = udf_vfsp->udf_lbsize << 3;
251 
252 	if (proximity != 0) {
253 		/*
254 		 * directly try allocating
255 		 * at proximity
256 		 */
257 		temp = blkcount;
258 		if (ud_check_free_and_mark_used(vfsp,
259 		    ud_part, proximity, &temp) == 0) {
260 			if (temp != 0) {
261 				*start_blkno = proximity;
262 				*size = temp;
263 				return (0);
264 			}
265 		}
266 		*start_blkno = 0;
267 		*size = 0;
268 	}
269 
270 	mutex_enter(&udf_vfsp->udf_lock);
271 	fragmented = udf_vfsp->udf_fragmented;
272 	mutex_exit(&udf_vfsp->udf_lock);
273 retry:
274 	old_loc = old_size = 0;
275 
276 	mutex_enter(&udf_vfsp->udf_lock);
277 	loop_begin = (ud_part->udp_last_alloc + CLSTR_MASK) & ~CLSTR_MASK;
278 	mutex_exit(&udf_vfsp->udf_lock);
279 
280 	loop_end = ud_part->udp_nblocks + HDR_BLKS;
281 	loop_count = (loop_begin) ? 2 : 1;
282 	while (loop_count--) {
283 		for (bno = loop_begin + HDR_BLKS; bno + blkcount < loop_end; ) {
284 
285 
286 			/*
287 			 * Each bread is restricted to lbsize
288 			 * due to the way bread is implemented
289 			 */
290 			if ((bp == NULL) ||
291 			    ((eblk - bno) < blkcount)) {
292 				if (bp != NULL) {
293 					brelse(bp);
294 				}
295 				begin = ud_part->udp_unall_loc +
296 				    bno / bb_count;
297 				bp = ud_bread(vfsp->vfs_dev,
298 				    ud_xlate_to_daddr(udf_vfsp,
299 				    ud_part->udp_number,
300 				    begin, 1, &dummy) <<
301 				    udf_vfsp->udf_l2d_shift, lbsz);
302 				if (bp->b_flags & B_ERROR) {
303 					brelse(bp);
304 					return (EIO);
305 				}
306 				bblk = begin * bb_count;
307 				eblk = bblk + bb_count;
308 				addr = (uint8_t *)bp->b_un.b_addr;
309 				eaddr = addr + bp->b_bcount;
310 			}
311 
312 			if (blkcount > (eblk - bno)) {
313 				temp = eblk - bno;
314 			} else {
315 				temp = blkcount;
316 			}
317 			if ((new_size = ud_check_free(addr, eaddr,
318 			    bno - bblk, temp)) == temp) {
319 				ud_mark_used(addr, bno - bblk, temp);
320 				bdwrite(bp);
321 				*start_blkno = bno - HDR_BLKS;
322 				*size = temp;
323 				mutex_enter(&udf_vfsp->udf_lock);
324 				ud_part->udp_last_alloc =
325 				    bno + temp - HDR_BLKS;
326 				mutex_exit(&udf_vfsp->udf_lock);
327 				return (0);
328 			}
329 			if (less_is_ok) {
330 				if (old_size < new_size) {
331 					old_loc = bno - HDR_BLKS;
332 					old_size = new_size;
333 				}
334 			}
335 			if (new_size != 0) {
336 				bno += new_size;
337 			} else {
338 #ifdef	SKIP_USED_BLOCKS
339 				/*
340 				 * Skipping 0's
341 				 * implement a allocated block skip
342 				 * using a while loop with an
343 				 * preinitialised array of 256 elements
344 				 * for number of blocks skipped
345 				 */
346 				bno &= ~3;
347 				while (skip[addr[(bno - bblk) >> 3]] == 8)
348 					bno += 8;
349 				bno += skip[addr[(bno - bblk) >> 3]];
350 #else
351 				bno++;
352 #endif
353 			}
354 			if (!fragmented) {
355 				bno = (bno + CLSTR_MASK) & ~CLSTR_MASK;
356 			}
357 		}
358 		if (bp != NULL) {
359 			brelse(bp);
360 			bp = NULL;
361 		}
362 		if (loop_count) {
363 			loop_end = loop_begin + HDR_BLKS;
364 			loop_begin = 0;
365 		}
366 	}
367 	if ((old_size == 0) && (!fragmented)) {
368 		mutex_enter(&udf_vfsp->udf_lock);
369 		fragmented = udf_vfsp->udf_fragmented = 1;
370 		mutex_exit(&udf_vfsp->udf_lock);
371 		goto retry;
372 	}
373 	if (less_is_ok && (old_size != 0)) {
374 
375 		/*
376 		 * Check once again
377 		 * somebody else might have
378 		 * already allocated behind us
379 		 */
380 		if (ud_check_free_and_mark_used(vfsp,
381 		    ud_part, old_loc, &old_size) == 0) {
382 			if (old_size != 0) {
383 				*start_blkno = old_loc;
384 				*size = old_size;
385 				mutex_enter(&udf_vfsp->udf_lock);
386 				ud_part->udp_last_alloc = old_loc + old_size;
387 				mutex_exit(&udf_vfsp->udf_lock);
388 				return (0);
389 			}
390 		}
391 
392 		/*
393 		 * Failed what ever the reason
394 		 */
395 		goto retry;
396 	}
397 	return (ENOSPC);
398 }
399 
400 /*
401  * start is the block from the begining
402  * of the partition ud_part
403  */
404 int32_t
405 ud_check_free_and_mark_used(struct vfs *vfsp,
406 	struct ud_part *ud_part, uint32_t start, uint32_t *count)
407 {
408 	struct buf *bp;
409 	struct udf_vfs *udf_vfsp;
410 	uint32_t begin, dummy, bb_count;
411 
412 	/*
413 	 * Adjust start for the header
414 	 */
415 	start += HDR_BLKS;
416 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
417 	bb_count = udf_vfsp->udf_lbsize << 3;
418 
419 	/*
420 	 * Read just on block worth of bitmap
421 	 */
422 	begin = ud_part->udp_unall_loc + (start / bb_count);
423 	bp = ud_bread(vfsp->vfs_dev,
424 	    ud_xlate_to_daddr(udf_vfsp, ud_part->udp_number,
425 	    begin, 1, &dummy) << udf_vfsp->udf_l2d_shift,
426 	    udf_vfsp->udf_lbsize);
427 	if (bp->b_flags & B_ERROR) {
428 		brelse(bp);
429 		return (EIO);
430 	}
431 
432 	/*
433 	 * Adjust the count if necessary
434 	 */
435 	start -= begin * bb_count;
436 	if ((start + *count) > bb_count) {
437 		*count = bb_count - start;
438 		ASSERT(*count > 0);
439 	}
440 	if (ud_check_free((uint8_t *)bp->b_un.b_addr,
441 	    (uint8_t *)bp->b_un.b_addr + bp->b_bcount, start,
442 	    *count) != *count) {
443 		brelse(bp);
444 		return (1);
445 	}
446 	ud_mark_used((uint8_t *)bp->b_un.b_addr, start, *count);
447 	bdwrite(bp);
448 
449 	return (0);
450 }
451 
452 int32_t
453 ud_check_free(uint8_t *addr, uint8_t *eaddr, uint32_t start, uint32_t count)
454 {
455 	int32_t i = 0;
456 
457 	for (i = 0; i < count; i++) {
458 		if (&addr[start >> 3] >= eaddr) {
459 			break;
460 		}
461 		if ((addr[start >> 3] & (1 << (start & 0x7))) == 0) {
462 			break;
463 		}
464 		start ++;
465 	}
466 	return (i);
467 }
468 
469 void
470 ud_mark_used(uint8_t *addr, uint32_t start, uint32_t count)
471 {
472 	int32_t i = 0;
473 
474 	for (i = 0; i < count; i++) {
475 		addr[start >> 3] &= ~(1 << (start & 0x7));
476 		start++;
477 	}
478 }
479 
480 void
481 ud_mark_free(uint8_t *addr, uint32_t start, uint32_t count)
482 {
483 	int32_t i = 0;
484 
485 	for (i = 0; i < count; i++) {
486 		addr[start >> 3] |= (1 << (start & 0x7));
487 		start++;
488 	}
489 }
490 
491 /* ARGSUSED */
492 int32_t
493 ud_alloc_space_stbl(struct vfs *vfsp,
494 	struct ud_part *ud_part, uint32_t proximity,
495 	uint32_t blkcount, uint32_t *start_blkno,
496 	uint32_t *size, int32_t less_is_ok)
497 {
498 	uint16_t adesc;
499 	uint32_t temp, sz;
500 	int32_t error, index, count, larg_index, larg_sz;
501 	struct buf *bp;
502 	struct udf_vfs *udf_vfsp;
503 	struct unall_space_ent *use;
504 
505 	ASSERT(ud_part);
506 	ASSERT(ud_part->udp_flags == UDP_SPACETBLS);
507 
508 	ud_printf("ud_alloc_space_stbl\n");
509 
510 	if (ud_part->udp_unall_len == 0) {
511 		return (ENOSPC);
512 	}
513 
514 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
515 	ASSERT((ud_part->udp_unall_len + 40) <= udf_vfsp->udf_lbsize);
516 
517 	bp = ud_bread(vfsp->vfs_dev,
518 	    ud_xlate_to_daddr(udf_vfsp, ud_part->udp_number,
519 	    ud_part->udp_unall_loc, 1, &temp), udf_vfsp->udf_lbsize);
520 
521 	use = (struct unall_space_ent *)bp->b_un.b_addr;
522 	sz = SWAP_32(use->use_len_ad);
523 	adesc = SWAP_16(use->use_icb_tag.itag_flags) & 0x7;
524 	if (adesc == ICB_FLAG_SHORT_AD) {
525 		struct short_ad *sad;
526 
527 		sad = (struct short_ad *)use->use_ad;
528 		count = sz / sizeof (struct short_ad);
529 
530 		/*
531 		 * Search the entire list for
532 		 * a extent which can give the entire data
533 		 * Do only first fit
534 		 */
535 		larg_index = larg_sz = 0;
536 		for (index = 0; index < count; index++, sad++) {
537 			temp = SWAP_32(sad->sad_ext_len) >>
538 			    udf_vfsp->udf_l2b_shift;
539 			if (temp == blkcount) {
540 				/*
541 				 * We found the right fit
542 				 * return the values and
543 				 * compress the table
544 				 */
545 				less_is_ok = 1;
546 				larg_index = index;
547 				larg_sz = temp;
548 				goto compress_sad;
549 			} else if (temp > blkcount) {
550 				/*
551 				 * We found an entry larger than the
552 				 * requirement. Change the start block
553 				 * number and the count to reflect the
554 				 * allocation
555 				 */
556 				*start_blkno = SWAP_32(sad->sad_ext_loc);
557 				*size = blkcount;
558 				temp = (temp - blkcount) <<
559 				    udf_vfsp->udf_l2b_shift;
560 				sad->sad_ext_len = SWAP_32(temp);
561 				temp = SWAP_32(sad->sad_ext_loc) + blkcount;
562 				sad->sad_ext_loc = SWAP_32(temp);
563 				goto end;
564 			}
565 			/*
566 			 * Let us keep track of the largest
567 			 * extent available if less_is_ok.
568 			 */
569 			if (less_is_ok) {
570 				if (temp > larg_sz) {
571 					larg_sz = temp;
572 					larg_index = index;
573 				}
574 			}
575 		}
576 compress_sad:
577 		if ((less_is_ok) && (larg_sz != 0)) {
578 			/*
579 			 * If we came here we could
580 			 * not find a extent to cover the entire size
581 			 * return whatever could be allocated
582 			 * and compress the table
583 			 */
584 			sad = (struct short_ad *)use->use_ad;
585 			sad += larg_index;
586 			*start_blkno = SWAP_32(sad->sad_ext_loc);
587 			*size = larg_sz;
588 			for (index = larg_index; index < count;
589 			    index++, sad++) {
590 				*sad = *(sad+1);
591 			}
592 			sz -= sizeof (struct short_ad);
593 			use->use_len_ad = SWAP_32(sz);
594 		} else {
595 			error = ENOSPC;
596 		}
597 		goto end;
598 	} else if (adesc == ICB_FLAG_LONG_AD) {
599 		struct long_ad *lad;
600 
601 		lad = (struct long_ad *)use->use_ad;
602 		count = sz / sizeof (struct long_ad);
603 
604 		/*
605 		 * Search the entire list for
606 		 * a extent which can give the entire data
607 		 * Do only first fit
608 		 */
609 		larg_index = larg_sz = 0;
610 		for (index = 0; index < count; index++, lad++) {
611 			temp = SWAP_32(lad->lad_ext_len) >>
612 			    udf_vfsp->udf_l2b_shift;
613 			if (temp == blkcount) {
614 				/*
615 				 * We found the right fit
616 				 * return the values and
617 				 * compress the table
618 				 */
619 				less_is_ok = 1;
620 				larg_index = index;
621 				larg_sz = temp;
622 				goto compress_lad;
623 			} else if (temp > blkcount) {
624 				/*
625 				 * We found an entry larger than the
626 				 * requirement. Change the start block
627 				 * number and the count to reflect the
628 				 * allocation
629 				 */
630 				*start_blkno = SWAP_32(lad->lad_ext_loc);
631 				*size = blkcount;
632 				temp = (temp - blkcount) <<
633 				    udf_vfsp->udf_l2b_shift;
634 				lad->lad_ext_len = SWAP_32(temp);
635 				temp = SWAP_32(lad->lad_ext_loc) + blkcount;
636 				lad->lad_ext_loc = SWAP_32(temp);
637 				goto end;
638 			}
639 			/*
640 			 * Let us keep track of the largest
641 			 * extent available if less_is_ok.
642 			 */
643 			if (less_is_ok) {
644 				if (temp > larg_sz) {
645 					larg_sz = temp;
646 					larg_index = index;
647 				}
648 			}
649 		}
650 compress_lad:
651 		if ((less_is_ok) && (larg_sz != 0)) {
652 			/*
653 			 * If we came here we could
654 			 * not find a extent to cover the entire size
655 			 * return whatever could be allocated
656 			 * and compress the table
657 			 */
658 			lad = (struct long_ad *)use->use_ad;
659 			lad += larg_index;
660 			*start_blkno = SWAP_32(lad->lad_ext_loc);
661 			*size = larg_sz;
662 			for (index = larg_index; index < count;
663 			    index++, lad++) {
664 				*lad = *(lad+1);
665 			}
666 			sz -= sizeof (struct long_ad);
667 			use->use_len_ad = SWAP_32(sz);
668 		} else {
669 			error = ENOSPC;
670 		}
671 		goto end;
672 	} else {
673 		error = ENOSPC;
674 	}
675 end:
676 	if (!error) {
677 		bdwrite(bp);
678 	} else {
679 		brelse(bp);
680 	}
681 	return (error);
682 }
683 
684 
685 /*
686  * release blkcount blocks starting from beginblk
687  * Call appropriate bmap/space table fucntions
688  */
689 void
690 ud_free_space(struct vfs *vfsp, uint16_t prn,
691 	uint32_t beginblk, uint32_t blkcount)
692 {
693 	int32_t i, error;
694 	struct ud_part *ud_part;
695 	struct udf_vfs *udf_vfsp;
696 
697 	ud_printf("ud_free_space\n");
698 
699 	if (blkcount == 0) {
700 		return;
701 	}
702 
703 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
704 	ud_part = udf_vfsp->udf_parts;
705 	for (i = 0; i < udf_vfsp->udf_npart; i++) {
706 		if (prn == ud_part->udp_number) {
707 			break;
708 		}
709 		ud_part ++;
710 	}
711 
712 	if (i == udf_vfsp->udf_npart) {
713 		return;
714 	}
715 
716 	if (ud_part->udp_flags == UDP_BITMAPS) {
717 		error = ud_free_space_bmap(vfsp, ud_part, beginblk, blkcount);
718 	} else {
719 		error = ud_free_space_stbl(vfsp, ud_part, beginblk, blkcount);
720 	}
721 
722 	if (error) {
723 		udf_vfsp->udf_mark_bad = 1;
724 	}
725 }
726 
727 /*
728  * If there is a freed table then
729  * release blocks to the freed table
730  * other wise release to the un allocated table.
731  * Findout the offset into the bitmap and
732  * mark the blocks as free blocks
733  */
734 int32_t
735 ud_free_space_bmap(struct vfs *vfsp,
736 	struct ud_part *ud_part,
737 	uint32_t beginblk, uint32_t blkcount)
738 {
739 	struct buf *bp;
740 	struct udf_vfs *udf_vfsp;
741 	uint32_t block, begin, end, blkno, count, map_end_blk, dummy;
742 
743 	ud_printf("ud_free_space_bmap\n");
744 
745 	ASSERT(ud_part);
746 	ASSERT(ud_part->udp_flags == UDP_BITMAPS);
747 /*
748  * prom_printf("%x %x\n", udblock, udcount);
749  */
750 
751 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
752 	if ((ud_part->udp_freed_len == 0) &&
753 	    (ud_part->udp_unall_len == 0)) {
754 		return (ENOSPC);
755 	}
756 	/*
757 	 * decide unallocated/freed table to use
758 	 */
759 	if (ud_part->udp_freed_len == 0) {
760 		begin = ud_part->udp_unall_loc;
761 		map_end_blk = ud_part->udp_unall_len << 3;
762 	} else {
763 		begin = ud_part->udp_freed_loc;
764 		map_end_blk = ud_part->udp_freed_len << 3;
765 	}
766 
767 	if (beginblk + blkcount > map_end_blk) {
768 		return (ENOSPC);
769 	}
770 
771 	/* adjust for the bitmap header */
772 	beginblk += HDR_BLKS;
773 
774 	end = begin + ((beginblk + blkcount) / (udf_vfsp->udf_lbsize << 3));
775 	begin += (beginblk / (udf_vfsp->udf_lbsize << 3));
776 
777 	for (block = begin; block <= end; block++) {
778 
779 		bp = ud_bread(vfsp->vfs_dev,
780 		    ud_xlate_to_daddr(udf_vfsp, ud_part->udp_number, block, 1,
781 		    &dummy) << udf_vfsp->udf_l2d_shift, udf_vfsp->udf_lbsize);
782 		if (bp->b_flags & B_ERROR) {
783 			brelse(bp);
784 			return (EIO);
785 		}
786 		ASSERT(dummy == 1);
787 
788 		mutex_enter(&udf_vfsp->udf_lock);
789 
790 		/*
791 		 * add freed blocks to the bitmap
792 		 */
793 
794 		blkno = beginblk - (block * (udf_vfsp->udf_lbsize << 3));
795 		if (blkno + blkcount > (udf_vfsp->udf_lbsize << 3)) {
796 			count = (udf_vfsp->udf_lbsize << 3) - blkno;
797 		} else {
798 			count = blkcount;
799 		}
800 
801 /*
802  * if (begin != end) {
803  *	printf("%x %x %x %x %x %x\n",
804  *		begin, end, block, blkno, count);
805  *	printf("%x %x %x\n", bp->b_un.b_addr, blkno, count);
806  * }
807  */
808 
809 		ud_mark_free((uint8_t *)bp->b_un.b_addr, blkno, count);
810 
811 		beginblk += count;
812 		blkcount -= count;
813 
814 		if (ud_part->udp_freed_len == 0) {
815 			ud_part->udp_nfree += count;
816 			udf_vfsp->udf_freeblks += count;
817 		}
818 		mutex_exit(&udf_vfsp->udf_lock);
819 
820 		bdwrite(bp);
821 	}
822 
823 	return (0);
824 }
825 
826 
827 /* ARGSUSED */
828 /*
829  * search the entire table if there is
830  * a entry with which we can merge the
831  * current entry. Other wise create
832  * a new entry at the end of the table
833  */
834 int32_t
835 ud_free_space_stbl(struct vfs *vfsp,
836 	struct ud_part *ud_part,
837 	uint32_t beginblk, uint32_t blkcount)
838 {
839 	uint16_t adesc;
840 	int32_t error = 0, index, count;
841 	uint32_t block, dummy, sz;
842 	struct buf *bp;
843 	struct udf_vfs *udf_vfsp;
844 	struct unall_space_ent *use;
845 
846 	ud_printf("ud_free_space_stbl\n");
847 
848 	ASSERT(ud_part);
849 	ASSERT(ud_part->udp_flags == UDP_SPACETBLS);
850 
851 	if ((ud_part->udp_freed_len == 0) && (ud_part->udp_unall_len == 0)) {
852 		return (ENOSPC);
853 	}
854 
855 	if (ud_part->udp_freed_len != 0) {
856 		block = ud_part->udp_freed_loc;
857 	} else {
858 		block = ud_part->udp_unall_loc;
859 	}
860 
861 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
862 	ASSERT((ud_part->udp_unall_len + 40) <= udf_vfsp->udf_lbsize);
863 
864 	bp = ud_bread(vfsp->vfs_dev,
865 	    ud_xlate_to_daddr(udf_vfsp, ud_part->udp_number, block, 1, &dummy),
866 	    udf_vfsp->udf_lbsize);
867 
868 	use = (struct unall_space_ent *)bp->b_un.b_addr;
869 	sz = SWAP_32(use->use_len_ad);
870 	adesc = SWAP_16(use->use_icb_tag.itag_flags) & 0x7;
871 	if (adesc == ICB_FLAG_SHORT_AD) {
872 		struct short_ad *sad;
873 
874 		sad = (struct short_ad *)use->use_ad;
875 		count = sz / sizeof (struct short_ad);
876 		/*
877 		 * Check if the blocks being freed
878 		 * are continuous with any of the
879 		 * existing extents
880 		 */
881 		for (index = 0; index < count; index++, sad++) {
882 			if (beginblk == (SWAP_32(sad->sad_ext_loc) +
883 			    (SWAP_32(sad->sad_ext_len) /
884 			    udf_vfsp->udf_lbsize))) {
885 				dummy = SWAP_32(sad->sad_ext_len) +
886 				    blkcount * udf_vfsp->udf_lbsize;
887 				sad->sad_ext_len = SWAP_32(dummy);
888 				goto end;
889 			} else if ((beginblk + blkcount) ==
890 			    SWAP_32(sad->sad_ext_loc)) {
891 				sad->sad_ext_loc = SWAP_32(beginblk);
892 				goto end;
893 			}
894 		}
895 
896 		/*
897 		 * We need to add a new entry
898 		 * Check if we space.
899 		 */
900 		if ((40 + sz + sizeof (struct short_ad)) >
901 		    udf_vfsp->udf_lbsize) {
902 			error = ENOSPC;
903 			goto end;
904 		}
905 
906 		/*
907 		 * We have enough space
908 		 * just add the entry at the end
909 		 */
910 		dummy = SWAP_32(use->use_len_ad);
911 		sad = (struct short_ad *)&use->use_ad[dummy];
912 		sz = blkcount * udf_vfsp->udf_lbsize;
913 		sad->sad_ext_len = SWAP_32(sz);
914 		sad->sad_ext_loc = SWAP_32(beginblk);
915 		dummy += sizeof (struct short_ad);
916 		use->use_len_ad = SWAP_32(dummy);
917 	} else if (adesc == ICB_FLAG_LONG_AD) {
918 		struct long_ad *lad;
919 
920 		lad = (struct long_ad *)use->use_ad;
921 		count = sz / sizeof (struct long_ad);
922 		/*
923 		 * Check if the blocks being freed
924 		 * are continuous with any of the
925 		 * existing extents
926 		 */
927 		for (index = 0; index < count; index++, lad++) {
928 			if (beginblk == (SWAP_32(lad->lad_ext_loc) +
929 			    (SWAP_32(lad->lad_ext_len) /
930 			    udf_vfsp->udf_lbsize))) {
931 				dummy = SWAP_32(lad->lad_ext_len) +
932 				    blkcount * udf_vfsp->udf_lbsize;
933 				lad->lad_ext_len = SWAP_32(dummy);
934 				goto end;
935 			} else if ((beginblk + blkcount) ==
936 			    SWAP_32(lad->lad_ext_loc)) {
937 				lad->lad_ext_loc = SWAP_32(beginblk);
938 				goto end;
939 			}
940 		}
941 
942 		/*
943 		 * We need to add a new entry
944 		 * Check if we space.
945 		 */
946 		if ((40 + sz + sizeof (struct long_ad)) >
947 		    udf_vfsp->udf_lbsize) {
948 			error = ENOSPC;
949 			goto end;
950 		}
951 
952 		/*
953 		 * We have enough space
954 		 * just add the entry at the end
955 		 */
956 		dummy = SWAP_32(use->use_len_ad);
957 		lad = (struct long_ad *)&use->use_ad[dummy];
958 		sz = blkcount * udf_vfsp->udf_lbsize;
959 		lad->lad_ext_len = SWAP_32(sz);
960 		lad->lad_ext_loc = SWAP_32(beginblk);
961 		lad->lad_ext_prn = SWAP_16(ud_part->udp_number);
962 		dummy += sizeof (struct long_ad);
963 		use->use_len_ad = SWAP_32(dummy);
964 	} else {
965 		error = ENOSPC;
966 		goto end;
967 	}
968 
969 end:
970 	if (!error) {
971 		bdwrite(bp);
972 	} else {
973 		brelse(bp);
974 	}
975 	return (error);
976 }
977 
978 /* ARGSUSED */
979 int32_t
980 ud_ialloc(struct ud_inode *pip,
981 	struct ud_inode **ipp, struct vattr *vap, struct cred *cr)
982 {
983 	int32_t err;
984 	uint32_t blkno, size, loc;
985 	uint32_t imode, ichar, lbsize, ea_len, dummy;
986 	uint16_t prn, flags;
987 	struct buf *bp;
988 	struct file_entry *fe;
989 	struct timespec32 time;
990 	struct timespec32 settime;
991 	struct icb_tag *icb;
992 	struct ext_attr_hdr *eah;
993 	struct dev_spec_ear *ds;
994 	struct udf_vfs *udf_vfsp;
995 	timestruc_t now;
996 	uid_t uid;
997 	gid_t gid;
998 
999 
1000 	ASSERT(pip);
1001 	ASSERT(vap != NULL);
1002 
1003 	ud_printf("ud_ialloc\n");
1004 
1005 	if (((vap->va_mask & AT_ATIME) && TIMESPEC_OVERFLOW(&vap->va_atime)) ||
1006 	    ((vap->va_mask & AT_MTIME) && TIMESPEC_OVERFLOW(&vap->va_mtime)))
1007 		return (EOVERFLOW);
1008 
1009 	udf_vfsp = pip->i_udf;
1010 	lbsize = udf_vfsp->udf_lbsize;
1011 	prn = pip->i_icb_prn;
1012 
1013 	if ((err = ud_alloc_space(pip->i_vfs, prn,
1014 	    0, 1, &blkno, &size, 0, 1)) != 0) {
1015 		return (err);
1016 	}
1017 	loc = ud_xlate_to_daddr(udf_vfsp, prn, blkno, 1, &dummy);
1018 	ASSERT(dummy == 1);
1019 
1020 	bp = ud_bread(pip->i_dev, loc << udf_vfsp->udf_l2d_shift, lbsize);
1021 	if (bp->b_flags & B_ERROR) {
1022 		ud_free_space(pip->i_vfs, prn, blkno, size);
1023 		return (EIO);
1024 	}
1025 	bzero(bp->b_un.b_addr, bp->b_bcount);
1026 	fe = (struct file_entry *)bp->b_un.b_addr;
1027 
1028 	uid = crgetuid(cr);
1029 	fe->fe_uid = SWAP_32(uid);
1030 
1031 	/*
1032 	 * To determine the group-id of the created file:
1033 	 * 1) If the gid is set in the attribute list (non-Sun & pre-4.0
1034 	 *	clients are not likely to set the gid), then use it if
1035 	 *	the process is privileged, belongs to the target group,
1036 	 *	or the group is the same as the parent directory.
1037 	 * 2) If the filesystem was not mounted with the Old-BSD-compatible
1038 	 *	GRPID option, and the directory's set-gid bit is clear,
1039 	 *	then use the process's gid.
1040 	 * 3) Otherwise, set the group-id to the gid of the parent directory.
1041 	 */
1042 	if ((vap->va_mask & AT_GID) &&
1043 	    ((vap->va_gid == pip->i_gid) || groupmember(vap->va_gid, cr) ||
1044 	    secpolicy_vnode_create_gid(cr) == 0)) {
1045 		/*
1046 		 * XXX - is this only the case when a 4.0 NFS client, or a
1047 		 * client derived from that code, makes a call over the wire?
1048 		 */
1049 		fe->fe_gid = SWAP_32(vap->va_gid);
1050 	} else {
1051 		gid = crgetgid(cr);
1052 		fe->fe_gid = (pip->i_char & ISGID) ?
1053 		    SWAP_32(pip->i_gid) : SWAP_32(gid);
1054 	}
1055 
1056 	imode = MAKEIMODE(vap->va_type, vap->va_mode);
1057 	ichar = imode & (VSUID | VSGID | VSVTX);
1058 	imode = UD_UPERM2DPERM(imode);
1059 
1060 	/*
1061 	 * Under solaris only the owner can
1062 	 * change the attributes of files so set
1063 	 * the change attribute bit only for user
1064 	 */
1065 	imode |= IATTR;
1066 
1067 	/*
1068 	 * File delete permissions on Solaris are
1069 	 * the permissions on the directory but not the file
1070 	 * when we create a file just inherit the directorys
1071 	 * write permission to be the file delete permissions
1072 	 * Atleast we will be consistent in the files we create
1073 	 */
1074 	imode |= (pip->i_perm & (IWRITE | IWRITE >> 5 | IWRITE >> 10)) << 3;
1075 
1076 	fe->fe_perms = SWAP_32(imode);
1077 
1078 	/*
1079 	 * udf does not have a "." entry in dir's
1080 	 * so even directories have only one link
1081 	 */
1082 	fe->fe_lcount = SWAP_16(1);
1083 
1084 	fe->fe_info_len = 0;
1085 	fe->fe_lbr = 0;
1086 
1087 	gethrestime(&now);
1088 	time.tv_sec = now.tv_sec;
1089 	time.tv_nsec = now.tv_nsec;
1090 	if (vap->va_mask & AT_ATIME) {
1091 		TIMESPEC_TO_TIMESPEC32(&settime, &vap->va_atime)
1092 		ud_utime2dtime(&settime, &fe->fe_acc_time);
1093 	} else
1094 		ud_utime2dtime(&time, &fe->fe_acc_time);
1095 	if (vap->va_mask & AT_MTIME) {
1096 		TIMESPEC_TO_TIMESPEC32(&settime, &vap->va_mtime)
1097 		ud_utime2dtime(&settime, &fe->fe_mod_time);
1098 	} else
1099 		ud_utime2dtime(&time, &fe->fe_mod_time);
1100 	ud_utime2dtime(&time, &fe->fe_attr_time);
1101 
1102 	ud_update_regid(&fe->fe_impl_id);
1103 
1104 	mutex_enter(&udf_vfsp->udf_lock);
1105 	fe->fe_uniq_id = SWAP_64(udf_vfsp->udf_maxuniq);
1106 	udf_vfsp->udf_maxuniq++;
1107 	mutex_exit(&udf_vfsp->udf_lock);
1108 
1109 	ea_len = 0;
1110 	if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) {
1111 		eah = (struct ext_attr_hdr *)fe->fe_spec;
1112 		ea_len = (sizeof (struct ext_attr_hdr) + 3) & ~3;
1113 		eah->eah_ial = SWAP_32(ea_len);
1114 
1115 		ds = (struct dev_spec_ear *)&fe->fe_spec[ea_len];
1116 		ea_len += ud_make_dev_spec_ear(ds,
1117 		    getmajor(vap->va_rdev), getminor(vap->va_rdev));
1118 		ea_len = (ea_len + 3) & ~3;
1119 		eah->eah_aal = SWAP_32(ea_len);
1120 		ud_make_tag(udf_vfsp, &eah->eah_tag,
1121 		    UD_EXT_ATTR_HDR, blkno, ea_len);
1122 	}
1123 
1124 	fe->fe_len_ear = SWAP_32(ea_len);
1125 	fe->fe_len_adesc = 0;
1126 
1127 	icb = &fe->fe_icb_tag;
1128 	icb->itag_prnde = 0;
1129 	icb->itag_strategy = SWAP_16(STRAT_TYPE4);
1130 	icb->itag_param = 0;
1131 	icb->itag_max_ent = SWAP_16(1);
1132 	switch (vap->va_type) {
1133 		case VREG :
1134 			icb->itag_ftype = FTYPE_FILE;
1135 			break;
1136 		case VDIR :
1137 			icb->itag_ftype = FTYPE_DIRECTORY;
1138 			break;
1139 		case VBLK :
1140 			icb->itag_ftype = FTYPE_BLOCK_DEV;
1141 			break;
1142 		case VCHR :
1143 			icb->itag_ftype = FTYPE_CHAR_DEV;
1144 			break;
1145 		case VLNK :
1146 			icb->itag_ftype = FTYPE_SYMLINK;
1147 			break;
1148 		case VFIFO :
1149 			icb->itag_ftype = FTYPE_FIFO;
1150 			break;
1151 		case VSOCK :
1152 			icb->itag_ftype = FTYPE_C_ISSOCK;
1153 			break;
1154 		default :
1155 			brelse(bp);
1156 			goto error;
1157 	}
1158 	icb->itag_lb_loc = 0;
1159 	icb->itag_lb_prn = 0;
1160 	flags = ICB_FLAG_ONE_AD;
1161 	if ((pip->i_char & ISGID) && (vap->va_type == VDIR)) {
1162 		ichar |= ISGID;
1163 	} else {
1164 		if ((ichar & ISGID) &&
1165 		    secpolicy_vnode_setids_setgids(cr,
1166 		    (gid_t)SWAP_32(fe->fe_gid)) != 0) {
1167 			ichar &= ~ISGID;
1168 		}
1169 	}
1170 	if (ichar & ISUID) {
1171 		flags |= ICB_FLAG_SETUID;
1172 	}
1173 	if (ichar & ISGID) {
1174 		flags |= ICB_FLAG_SETGID;
1175 	}
1176 	if (ichar & ISVTX) {
1177 		flags |= ICB_FLAG_STICKY;
1178 	}
1179 	icb->itag_flags = SWAP_16(flags);
1180 	ud_make_tag(udf_vfsp, &fe->fe_tag, UD_FILE_ENTRY, blkno,
1181 	    offsetof(struct file_entry, fe_spec) +
1182 	    SWAP_32(fe->fe_len_ear) + SWAP_32(fe->fe_len_adesc));
1183 
1184 	BWRITE2(bp);
1185 
1186 	mutex_enter(&udf_vfsp->udf_lock);
1187 	if (vap->va_type == VDIR) {
1188 		udf_vfsp->udf_ndirs++;
1189 	} else {
1190 		udf_vfsp->udf_nfiles++;
1191 	}
1192 	mutex_exit(&udf_vfsp->udf_lock);
1193 
1194 #ifdef	DEBUG
1195 	{
1196 		struct ud_inode *ip;
1197 
1198 		if ((ip = ud_search_icache(pip->i_vfs, prn, blkno)) != NULL) {
1199 			cmn_err(CE_NOTE, "duplicate %p %x\n",
1200 			    (void *)ip, (uint32_t)ip->i_icb_lbano);
1201 		}
1202 	}
1203 #endif
1204 
1205 	if ((err = ud_iget(pip->i_vfs, prn, blkno, ipp, bp, cr)) != 0) {
1206 error:
1207 		ud_free_space(pip->i_vfs, prn, blkno, size);
1208 		return (err);
1209 	}
1210 
1211 	return (0);
1212 
1213 noinodes:
1214 	cmn_err(CE_NOTE, "%s: out of inodes\n", pip->i_udf->udf_volid);
1215 	return (ENOSPC);
1216 }
1217 
1218 
1219 void
1220 ud_ifree(struct ud_inode *ip, vtype_t type)
1221 {
1222 	struct udf_vfs *udf_vfsp;
1223 	struct buf *bp;
1224 
1225 	ud_printf("ud_ifree\n");
1226 
1227 	if (ip->i_vfs == NULL) {
1228 		return;
1229 	}
1230 
1231 	udf_vfsp = (struct udf_vfs *)ip->i_vfs->vfs_data;
1232 	bp = ud_bread(ip->i_dev, ip->i_icb_lbano <<
1233 	    udf_vfsp->udf_l2d_shift, udf_vfsp->udf_lbsize);
1234 	if (bp->b_flags & B_ERROR) {
1235 		/*
1236 		 * Error get rid of bp
1237 		 */
1238 		brelse(bp);
1239 	} else {
1240 		/*
1241 		 * Just trash the inode
1242 		 */
1243 		bzero(bp->b_un.b_addr, 0x10);
1244 		BWRITE(bp);
1245 	}
1246 	ud_free_space(ip->i_vfs, ip->i_icb_prn, ip->i_icb_block, 1);
1247 	mutex_enter(&udf_vfsp->udf_lock);
1248 	if (type == VDIR) {
1249 		if (udf_vfsp->udf_ndirs > 1) {
1250 			udf_vfsp->udf_ndirs--;
1251 		}
1252 	} else {
1253 		if (udf_vfsp->udf_nfiles > 0) {
1254 			udf_vfsp->udf_nfiles --;
1255 		}
1256 	}
1257 	mutex_exit(&udf_vfsp->udf_lock);
1258 }
1259 
1260 
1261 /*
1262  * Free storage space associated with the specified inode.  The portion
1263  * to be freed is specified by lp->l_start and lp->l_len (already
1264  * normalized to a "whence" of 0).
1265  *
1266  * This is an experimental facility whose continued existence is not
1267  * guaranteed.  Currently, we only support the special case
1268  * of l_len == 0, meaning free to end of file.
1269  *
1270  * Blocks are freed in reverse order.  This FILO algorithm will tend to
1271  * maintain a contiguous free list much longer than FIFO.
1272  * See also ufs_itrunc() in ufs_inode.c.
1273  *
1274  * Bug: unused bytes in the last retained block are not cleared.
1275  * This may result in a "hole" in the file that does not read as zeroes.
1276  */
1277 int32_t
1278 ud_freesp(struct vnode *vp,
1279 	struct flock64 *lp,
1280 	int32_t flag, struct cred *cr)
1281 {
1282 	int32_t i;
1283 	struct ud_inode *ip = VTOI(vp);
1284 	int32_t error;
1285 
1286 	ASSERT(vp->v_type == VREG);
1287 	ASSERT(lp->l_start >= (offset_t)0);	/* checked by convoff */
1288 
1289 	ud_printf("udf_freesp\n");
1290 
1291 	if (lp->l_len != 0) {
1292 		return (EINVAL);
1293 	}
1294 
1295 	rw_enter(&ip->i_contents, RW_READER);
1296 	if (ip->i_size == (u_offset_t)lp->l_start) {
1297 		rw_exit(&ip->i_contents);
1298 		return (0);
1299 	}
1300 
1301 	/*
1302 	 * Check if there is any active mandatory lock on the
1303 	 * range that will be truncated/expanded.
1304 	 */
1305 	if (MANDLOCK(vp, ip->i_char)) {
1306 		offset_t save_start;
1307 
1308 		save_start = lp->l_start;
1309 
1310 		if (ip->i_size < lp->l_start) {
1311 			/*
1312 			 * "Truncate up" case: need to make sure there
1313 			 * is no lock beyond current end-of-file. To
1314 			 * do so, we need to set l_start to the size
1315 			 * of the file temporarily.
1316 			 */
1317 			lp->l_start = ip->i_size;
1318 		}
1319 		lp->l_type = F_WRLCK;
1320 		lp->l_sysid = 0;
1321 		lp->l_pid = ttoproc(curthread)->p_pid;
1322 		i = (flag & (FNDELAY|FNONBLOCK)) ? 0 : SLPFLCK;
1323 		rw_exit(&ip->i_contents);
1324 		if ((i = reclock(vp, lp, i, 0, lp->l_start, NULL)) != 0 ||
1325 		    lp->l_type != F_UNLCK) {
1326 			return (i ? i : EAGAIN);
1327 		}
1328 		rw_enter(&ip->i_contents, RW_READER);
1329 
1330 		lp->l_start = save_start;
1331 	}
1332 	/*
1333 	 * Make sure a write isn't in progress (allocating blocks)
1334 	 * by acquiring i_rwlock (we promised ufs_bmap we wouldn't
1335 	 * truncate while it was allocating blocks).
1336 	 * Grab the locks in the right order.
1337 	 */
1338 	rw_exit(&ip->i_contents);
1339 	rw_enter(&ip->i_rwlock, RW_WRITER);
1340 	rw_enter(&ip->i_contents, RW_WRITER);
1341 	error = ud_itrunc(ip, lp->l_start, 0, cr);
1342 	rw_exit(&ip->i_contents);
1343 	rw_exit(&ip->i_rwlock);
1344 	return (error);
1345 }
1346 
1347 
1348 
1349 /*
1350  * Cache is implemented by
1351  * allocating a cluster of blocks
1352  */
1353 int32_t
1354 ud_alloc_from_cache(struct udf_vfs *udf_vfsp,
1355 	struct ud_part *part, uint32_t *blkno)
1356 {
1357 	uint32_t bno, sz;
1358 	int32_t error, index, free = 0;
1359 
1360 	ud_printf("ud_alloc_from_cache\n");
1361 
1362 	ASSERT(udf_vfsp);
1363 
1364 	mutex_enter(&udf_vfsp->udf_lock);
1365 	if (part->udp_cache_count == 0) {
1366 		mutex_exit(&udf_vfsp->udf_lock);
1367 		/* allocate new cluster */
1368 		if ((error = ud_alloc_space(udf_vfsp->udf_vfs,
1369 		    part->udp_number, 0, CLSTR_SIZE, &bno, &sz, 1, 0)) != 0) {
1370 			return (error);
1371 		}
1372 		if (sz == 0) {
1373 			return (ENOSPC);
1374 		}
1375 		mutex_enter(&udf_vfsp->udf_lock);
1376 		if (part->udp_cache_count == 0) {
1377 			for (index = 0; index < sz; index++, bno++) {
1378 				part->udp_cache[index] = bno;
1379 			}
1380 			part->udp_cache_count = sz;
1381 		} else {
1382 			free = 1;
1383 		}
1384 	}
1385 	part->udp_cache_count--;
1386 	*blkno = part->udp_cache[part->udp_cache_count];
1387 	mutex_exit(&udf_vfsp->udf_lock);
1388 	if (free) {
1389 		ud_free_space(udf_vfsp->udf_vfs, part->udp_number, bno, sz);
1390 	}
1391 	return (0);
1392 }
1393 
1394 /*
1395  * Will be called from unmount
1396  */
1397 int32_t
1398 ud_release_cache(struct udf_vfs *udf_vfsp)
1399 {
1400 	int32_t i, error = 0;
1401 	struct ud_part *part;
1402 	uint32_t start, nblks;
1403 
1404 	ud_printf("ud_release_cache\n");
1405 
1406 	mutex_enter(&udf_vfsp->udf_lock);
1407 	part = udf_vfsp->udf_parts;
1408 	for (i = 0; i < udf_vfsp->udf_npart; i++, part++) {
1409 		if (part->udp_cache_count) {
1410 			nblks = part->udp_cache_count;
1411 			start = part->udp_cache[0];
1412 			part->udp_cache_count = 0;
1413 			mutex_exit(&udf_vfsp->udf_lock);
1414 			ud_free_space(udf_vfsp->udf_vfs,
1415 			    part->udp_number, start, nblks);
1416 			mutex_enter(&udf_vfsp->udf_lock);
1417 		}
1418 	}
1419 	mutex_exit(&udf_vfsp->udf_lock);
1420 	return (error);
1421 }
1422