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