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
68 #include <vm/hat.h>
69 #include <vm/page.h>
70 #include <vm/pvn.h>
71 #include <vm/as.h>
72 #include <vm/seg.h>
73 #include <vm/seg_map.h>
74 #include <vm/seg_kmem.h>
75 #include <vm/seg_vn.h>
76 #include <vm/rm.h>
77 #include <vm/page.h>
78 #include <sys/swap.h>
79
80
81 #include <fs/fs_subr.h>
82
83
84 #include <sys/fs/udf_volume.h>
85 #include <sys/fs/udf_inode.h>
86
87
88 int32_t ud_break_create_new_icb(struct ud_inode *, int32_t, uint32_t);
89 int32_t ud_bump_ext_count(struct ud_inode *, int32_t);
90 void ud_remove_ext_at_index(struct ud_inode *, int32_t);
91 int32_t ud_last_alloc_ext(struct ud_inode *, uint64_t, uint32_t, int32_t);
92 int32_t ud_create_ext(struct ud_inode *, int32_t, uint32_t,
93 int32_t, uint64_t, uint64_t *);
94 int32_t ud_zero_it(struct ud_inode *, uint32_t, uint32_t);
95
96 #define ALLOC_SPACE 0x01
97 #define NEW_EXT 0x02
98
99 #define MEXT_BITS 30
100
101 int32_t
ud_bmap_has_holes(struct ud_inode * ip)102 ud_bmap_has_holes(struct ud_inode *ip)
103 {
104 int32_t i, error = 0;
105 struct icb_ext *iext;
106
107 ud_printf("ud_bmap_has_holes\n");
108
109 ASSERT(RW_LOCK_HELD(&ip->i_contents));
110
111 /* ICB_FLAG_ONE_AD is always continuos */
112 if (ip->i_desc_type != ICB_FLAG_ONE_AD) {
113 if ((error = ud_read_icb_till_off(ip, ip->i_size)) == 0) {
114 for (i = 0; i < ip->i_ext_used; i++) {
115 iext = &ip->i_ext[i];
116 if (iext->ib_flags == IB_UN_RE_AL) {
117 error = 1;
118 break;
119 }
120 }
121 }
122 }
123
124 return (error);
125 }
126
127 int32_t
ud_bmap_read(struct ud_inode * ip,u_offset_t off,daddr_t * bnp,int32_t * lenp)128 ud_bmap_read(struct ud_inode *ip, u_offset_t off, daddr_t *bnp, int32_t *lenp)
129 {
130 struct icb_ext *iext;
131 daddr_t bno;
132 int32_t lbmask, i, l2b, l2d, error = 0, count;
133 uint32_t length, block, dummy;
134
135 ud_printf("ud_bmap_read\n");
136
137 ASSERT(RW_LOCK_HELD(&ip->i_contents));
138
139 lbmask = ip->i_udf->udf_lbmask;
140 l2b = ip->i_udf->udf_l2b_shift;
141 l2d = ip->i_udf->udf_l2d_shift;
142
143 if ((error = ud_read_icb_till_off(ip, ip->i_size)) == 0) {
144 for (i = 0; i < ip->i_ext_used; i++) {
145 iext = &ip->i_ext[i];
146 if ((iext->ib_offset <= off) &&
147 (off < (iext->ib_offset + iext->ib_count))) {
148 length = ((iext->ib_offset +
149 iext->ib_count - off) +
150 lbmask) & ~lbmask;
151 if (iext->ib_flags == IB_UN_RE_AL) {
152 *bnp = UDF_HOLE;
153 *lenp = length;
154 break;
155 }
156
157 block = iext->ib_block +
158 ((off - iext->ib_offset) >> l2b);
159 count = length >> l2b;
160
161 bno = ud_xlate_to_daddr(ip->i_udf,
162 iext->ib_prn, block, count, &dummy);
163 ASSERT(dummy != 0);
164 ASSERT(dummy <= count);
165 *bnp = bno << l2d;
166 *lenp = dummy << l2b;
167
168 break;
169 }
170 }
171 if (i == ip->i_ext_used) {
172 error = EINVAL;
173 }
174 }
175
176 return (error);
177 }
178
179
180 /*
181 * Extent allocation in the inode
182 * Initially when the inode is allocated we
183 * will allocate EXT_PER_MALLOC extents and once these
184 * are used we allocate another 10 and copy
185 * the old extents and start using the others
186 */
187 #define BASE(count) ((count) & ~lbmask)
188 #define CEIL(count) (((count) + lbmask) & ~lbmask)
189
190 #define PBASE(count) ((count) & PAGEMASK)
191 #define PCEIL(count) (((count) + PAGEOFFSET) & PAGEMASK)
192
193
194 /* ARGSUSED3 */
195 int32_t
ud_bmap_write(struct ud_inode * ip,u_offset_t off,int32_t size,int32_t alloc_only,struct cred * cr)196 ud_bmap_write(struct ud_inode *ip,
197 u_offset_t off, int32_t size, int32_t alloc_only, struct cred *cr)
198 {
199 int32_t error = 0, i, isdir, issync;
200 struct udf_vfs *udf_vfsp;
201 struct icb_ext *iext, *pext;
202 uint32_t blkno, sz;
203 u_offset_t isize;
204 uint32_t acount, prox;
205 int32_t blkcount, next;
206 int32_t lbmask, l2b;
207 uint64_t end_req, end_ext, mext_sz, icb_offset, count;
208 int32_t dtype_changed = 0, memory_allocated = 0;
209 struct fbuf *fbp = NULL;
210
211
212 ud_printf("ud_bmap_write\n");
213
214 ASSERT(RW_WRITE_HELD(&ip->i_contents));
215
216 udf_vfsp = ip->i_udf;
217 lbmask = udf_vfsp->udf_lbmask;
218 l2b = udf_vfsp->udf_l2b_shift;
219 mext_sz = (1 << MEXT_BITS) - PAGESIZE;
220
221 if (lblkno(udf_vfsp, off) < 0) {
222 return (EFBIG);
223 }
224
225 issync = ((ip->i_flag & ISYNC) != 0);
226
227 isdir = (ip->i_type == VDIR);
228 if (isdir || issync) {
229 alloc_only = 0; /* make sure */
230 }
231
232 end_req = BASE(off) + size;
233 if (ip->i_desc_type == ICB_FLAG_ONE_AD) {
234 if (end_req < ip->i_max_emb) {
235 goto out;
236 }
237
238 if (ip->i_size != 0) {
239 error = fbread(ITOV(ip), 0, ip->i_size, S_OTHER, &fbp);
240 if (error != 0) {
241 goto out;
242 }
243 } else {
244 fbp = NULL;
245 }
246 /*
247 * Change the desc_type
248 */
249 ip->i_desc_type = ICB_FLAG_SHORT_AD;
250 dtype_changed = 1;
251
252 one_ad_no_i_ext:
253 ASSERT(ip->i_ext == NULL);
254 ASSERT(ip->i_astrat == STRAT_TYPE4);
255
256 ip->i_ext_used = 0;
257 ip->i_cur_max_ext = ip->i_max_emb / sizeof (struct short_ad);
258 ip->i_cur_max_ext --;
259 if (end_req > mext_sz) {
260 next = end_req / mext_sz;
261 } else {
262 next = 1;
263 }
264 ip->i_ext_count =
265 ((next / EXT_PER_MALLOC) + 1) * EXT_PER_MALLOC;
266 iext = ip->i_ext = (struct icb_ext *)kmem_zalloc(
267 ip->i_ext_count * sizeof (struct icb_ext), KM_SLEEP);
268 memory_allocated = 1;
269
270 /* There will be atleast EXT_PER_MALLOC icb_ext's allocated */
271
272 one_ad_i_ext:
273 icb_offset = 0;
274 count = end_req;
275
276 /* Can we create a HOLE */
277
278 if ((PCEIL(ip->i_size) < PBASE(off)) &&
279 ((PBASE(off) - PCEIL(ip->i_size)) >= PAGESIZE)) {
280
281 if (ip->i_size != 0) {
282
283 /*
284 * Allocate one block for
285 * old data.(cannot be more than one page)
286 */
287
288 count = PAGESIZE;
289 if (error = ud_create_ext(ip, ip->i_ext_used,
290 ALLOC_SPACE | NEW_EXT, alloc_only,
291 icb_offset, &count)) {
292 goto embedded_error;
293 }
294 icb_offset = PAGESIZE;
295 }
296
297 /*
298 * Allocate a hole from PCEIL(ip->i_size) to PBASE(off)
299 */
300
301 count = PBASE(off) - PCEIL(ip->i_size);
302 (void) ud_create_ext(ip, ip->i_ext_used, NEW_EXT,
303 alloc_only, icb_offset, &count);
304 icb_offset = PBASE(off);
305
306 /*
307 * Allocate the rest of the space PBASE(off) to end_req
308 */
309 count = end_req - PBASE(off);
310 } else {
311 /*
312 * If no hole can be created then allocate
313 * space till the end of the request
314 */
315 count = end_req;
316 }
317
318
319
320 if (error = ud_create_ext(ip, ip->i_ext_used,
321 ALLOC_SPACE | NEW_EXT,
322 alloc_only, icb_offset, &count)) {
323 embedded_error:
324 /*
325 * Something error
326 * most probable file system is full
327 * we know that the file came in as a embedded file.
328 * undo what ever we did in this block of code
329 */
330 if (dtype_changed) {
331 ip->i_desc_type = ICB_FLAG_ONE_AD;
332 }
333 for (i = 0; i < ip->i_ext_used; i++) {
334 iext = &ip->i_ext[i];
335 if (iext->ib_flags != IB_UN_RE_AL) {
336 ud_free_space(ip->i_udf->udf_vfs,
337 iext->ib_prn, iext->ib_block,
338 (iext->ib_count + lbmask) >>
339 l2b);
340 }
341 }
342 if (memory_allocated) {
343 kmem_free(ip->i_ext,
344 ip->i_ext_count *
345 sizeof (struct icb_ext));
346 ip->i_ext = NULL;
347 ip->i_ext_count = ip->i_ext_used = 0;
348 }
349 }
350
351 if (fbp != NULL) {
352 fbrelse(fbp, S_WRITE);
353 }
354
355 return (error);
356 } else {
357
358 /*
359 * Type 4 directories being created
360 */
361 if (ip->i_ext == NULL) {
362 goto one_ad_no_i_ext;
363 }
364
365 /*
366 * Read the entire icb's to memory
367 */
368 if (ud_read_icb_till_off(ip, ip->i_size) != 0) {
369 error = EINVAL;
370 goto out;
371 }
372
373 isize = CEIL(ip->i_size);
374
375 if (end_req > isize) {
376
377 /*
378 * The new file size is greater
379 * than the old size
380 */
381
382 if (ip->i_ext == NULL) {
383 goto one_ad_no_i_ext;
384 } else if (ip->i_ext_used == 0) {
385 goto one_ad_i_ext;
386 }
387
388 error = ud_last_alloc_ext(ip, off, size, alloc_only);
389
390 return (error);
391 } else {
392
393 /*
394 * File growing the new size will be less than
395 * iext->ib_offset + CEIL(iext->ib_count)
396 */
397
398 iext = &ip->i_ext[ip->i_ext_used - 1];
399
400 if (end_req > (iext->ib_offset + iext->ib_count)) {
401
402 iext->ib_count = end_req - iext->ib_offset;
403
404 if (iext->ib_flags != IB_UN_RE_AL) {
405 error = 0;
406 goto out;
407 }
408 }
409 }
410 }
411
412 /* By this point the end of last extent is >= BASE(off) + size */
413
414 ASSERT(ip->i_ext);
415
416 /*
417 * Figure out the icb_ext that has offset "off"
418 */
419 for (i = 0; i < ip->i_ext_used; i++) {
420 iext = &ip->i_ext[i];
421 if ((iext->ib_offset <= off) &&
422 ((iext->ib_offset + iext->ib_count) > off)) {
423 break;
424 }
425 }
426
427 /*
428 * iext will have offset "off"
429 */
430
431
432 do {
433 iext = &ip->i_ext[i];
434
435 if ((iext->ib_flags & IB_UN_RE_AL) == 0) {
436
437 /*
438 * Already allocated do nothing
439 */
440
441 i++;
442 } else {
443
444 /*
445 * We are in a hole.
446 * allocate the required space
447 * while trying to create smaller holes
448 */
449
450 if ((PBASE(off) > PBASE(iext->ib_offset)) &&
451 ((PBASE(off) - PBASE(iext->ib_offset)) >=
452 PAGESIZE)) {
453
454 /*
455 * Allocate space from begining of
456 * old hole to the begining of new hole
457 * We want all holes created by us
458 * to be MMUPAGE Aligned
459 */
460
461 if (PBASE(iext->ib_offset) !=
462 BASE(iext->ib_offset)) {
463 if ((error = ud_break_create_new_icb(
464 ip, i, BASE(iext->ib_offset) -
465 PBASE(iext->ib_offset))) != 0) {
466 return (error);
467 }
468 goto alloc_cur_ext;
469 }
470
471 /*
472 * Create the new hole
473 */
474
475 if ((error = ud_break_create_new_icb(ip, i,
476 PBASE(off) - iext->ib_offset)) != 0) {
477 return (error);
478 }
479 iext = &ip->i_ext[i];
480 i++;
481 continue;
482 }
483
484 end_ext = iext->ib_offset + iext->ib_count;
485
486 if ((PBASE(end_ext) > PCEIL(end_req)) &&
487 ((PBASE(end_ext) - PCEIL(end_req)) >=
488 PAGESIZE)) {
489 /*
490 * We can create a hole
491 * from PCEIL(end_req) - BASE(end_ext)
492 */
493 if ((error = ud_break_create_new_icb(ip, i,
494 PCEIL(end_req) - iext->ib_offset)) != 0) {
495 return (error);
496 }
497 }
498
499
500 alloc_cur_ext:
501 /*
502 * Allocate the current extent
503 */
504
505
506 /*
507 * If the previous extent
508 * is allocated then try to allocate
509 * adjascent to the previous extent
510 */
511 prox = 0;
512 if (i != 0) {
513 pext = &ip->i_ext[i - 1];
514 if (pext->ib_flags != IB_UN_RE_AL) {
515 prox = pext->ib_block +
516 (CEIL(pext->ib_count) >> l2b);
517 }
518 }
519
520 iext = &ip->i_ext[i];
521 blkcount = CEIL(iext->ib_count) >> l2b;
522
523 if ((error = ud_alloc_space(ip->i_vfs,
524 ip->i_icb_prn, prox, blkcount,
525 &blkno, &sz, 1, 0)) != 0) {
526 return (error);
527 }
528 ip->i_lbr += sz;
529 if (sz == 0) {
530 return (ENOSPC);
531 }
532
533 if (alloc_only == 0) {
534 error = ud_zero_it(ip, blkno, sz);
535 }
536
537 acount = sz << l2b;
538 if ((prox == blkno) &&
539 ((pext->ib_count + acount) < mext_sz)) {
540
541 /*
542 * We are able to allocate adjascent to
543 * the previous extent. Increment the
544 * previous extent count if the size
545 * of the extent is not greater than
546 * max extent size
547 */
548
549 pext = &ip->i_ext[i - 1];
550 pext->ib_count += acount;
551
552 if (sz == blkcount) {
553 /*
554 * and get rid of the current
555 * extent since we have
556 * allocated all of its size
557 * and incremented the
558 * previous extents count
559 */
560 ud_remove_ext_at_index(ip, i);
561 } else {
562 /*
563 * reduce the count of the
564 * current extent by the amount
565 * allocated in the last extent
566 */
567 ASSERT(acount < iext->ib_count);
568 iext->ib_count -= acount;
569 iext->ib_offset += acount;
570 }
571 } else {
572 if (sz < blkcount) {
573 if ((error = ud_break_create_new_icb(
574 ip, i, sz << l2b)) != 0) {
575 return (error);
576 }
577 }
578 iext = &ip->i_ext[i];
579 count -= CEIL(iext->ib_count);
580 iext->ib_prn = ip->i_icb_prn;
581 iext->ib_block = blkno;
582 iext->ib_flags &= ~IB_UN_RE_AL;
583 /*
584 * iext->ib_flags |= IB_UN_REC;
585 */
586 i++;
587 continue;
588 }
589 }
590 } while ((iext->ib_offset + iext->ib_count) < end_req);
591
592 out:
593 return (error);
594 }
595
596
597 /*
598 * increase i_con/i_ext arrays and set new elements
599 * using long or short allocation descriptors
600 */
601 static void
ud_common_ad(struct ud_inode * ip,struct buf * bp)602 ud_common_ad(struct ud_inode *ip, struct buf *bp)
603 {
604 int32_t ndesc, count, lbmask;
605 uint32_t length;
606 struct alloc_ext_desc *aed;
607 struct icb_ext *iext, *con;
608 u_offset_t offset;
609 long_ad_t *lad;
610 short_ad_t *sad;
611 int islong;
612 void *addr;
613
614 addr = bp->b_un.b_addr + sizeof (struct alloc_ext_desc);
615 aed = (struct alloc_ext_desc *)bp->b_un.b_addr;
616 length = SWAP_32(aed->aed_len_aed);
617 if (ip->i_desc_type == ICB_FLAG_LONG_AD) {
618 islong = 1;
619 lad = addr;
620 ndesc = length / sizeof (*lad);
621 } else if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
622 islong = 0;
623 sad = addr;
624 ndesc = length / sizeof (*sad);
625 } else
626 return;
627
628 /*
629 * realloc i_ext array
630 */
631 count = (((ip->i_ext_used + ndesc) / EXT_PER_MALLOC) + 1) *
632 EXT_PER_MALLOC;
633 addr = kmem_zalloc(count * sizeof (struct icb_ext), KM_SLEEP);
634 bcopy(ip->i_ext, addr, ip->i_ext_used * sizeof (struct icb_ext));
635 kmem_free(ip->i_ext, ip->i_ext_count * sizeof (struct icb_ext));
636 ip->i_ext = addr;
637 ip->i_ext_count = count;
638
639 /*
640 * scan descriptors
641 */
642 lbmask = ip->i_udf->udf_lbmask;
643 iext = &ip->i_ext[ip->i_ext_used - 1];
644 offset = iext->ib_offset + iext->ib_count;
645 iext++;
646 while (ndesc--) {
647 if (islong)
648 length = SWAP_32(lad->lad_ext_len);
649 else
650 length = SWAP_32(sad->sad_ext_len);
651
652 if ((length & 0x3FFFFFFF) == 0)
653 break;
654 else if (((length >> 30) & IB_MASK) == IB_CON) {
655 if (ip->i_con_used == ip->i_con_count) {
656 struct icb_ext *old;
657 int32_t old_count;
658
659 old = ip->i_con;
660 old_count = ip->i_con_count *
661 sizeof (struct icb_ext);
662 ip->i_con_count += EXT_PER_MALLOC;
663 ip->i_con = kmem_zalloc(ip->i_con_count *
664 sizeof (struct icb_ext), KM_SLEEP);
665
666 if (old) {
667 bcopy(old, ip->i_con, old_count);
668 kmem_free(old, old_count);
669 }
670 }
671 con = &ip->i_con[ip->i_con_used];
672 if (islong) {
673 con->ib_prn = SWAP_16(lad->lad_ext_prn);
674 con->ib_block = SWAP_32(lad->lad_ext_loc);
675 } else {
676 con->ib_prn = ip->i_icb_prn;
677 con->ib_block = SWAP_32(sad->sad_ext_loc);
678 }
679 con->ib_count = length & 0x3FFFFFFF;
680 con->ib_flags = (length >> 30) & IB_MASK;
681 ip->i_con_used++;
682 break;
683 }
684
685 if (islong) {
686 iext->ib_prn = SWAP_16(lad->lad_ext_prn);
687 iext->ib_block = SWAP_32(lad->lad_ext_loc);
688 lad++;
689 } else {
690 iext->ib_prn = 0;
691 iext->ib_block = SWAP_32(sad->sad_ext_loc);
692 sad++;
693 }
694 iext->ib_count = length & 0x3FFFFFFF;
695 iext->ib_offset = offset;
696 iext->ib_marker1 = (uint32_t)0xAAAAAAAA;
697 iext->ib_marker2 = (uint32_t)0xBBBBBBBB;
698 offset += (iext->ib_count + lbmask) & (~lbmask);
699 iext->ib_flags = (length >> 30) & IB_MASK;
700 ip->i_ext_used++;
701 iext++;
702 }
703 }
704
705
706 static int32_t
ud_read_next_cont(struct ud_inode * ip)707 ud_read_next_cont(struct ud_inode *ip)
708 {
709 uint32_t dummy, error = 0;
710 struct alloc_ext_desc *aed;
711 struct icb_ext *cont;
712 struct buf *bp;
713 daddr_t bno;
714
715 cont = &ip->i_con[ip->i_con_read];
716 ASSERT(cont->ib_count > 0);
717
718 bno = ud_xlate_to_daddr(ip->i_udf, cont->ib_prn, cont->ib_block,
719 1, &dummy);
720 bp = ud_bread(ip->i_dev, bno << ip->i_udf->udf_l2d_shift,
721 cont->ib_count);
722 if (bp->b_flags & B_ERROR)
723 error = bp->b_error;
724 else {
725 aed = (struct alloc_ext_desc *)bp->b_un.b_addr;
726 if (ud_verify_tag_and_desc(&aed->aed_tag, UD_ALLOC_EXT_DESC,
727 cont->ib_block, 1, cont->ib_count))
728 error = EINVAL;
729 }
730
731 if (error == 0)
732 ud_common_ad(ip, bp);
733
734 brelse(bp);
735 return (error);
736 }
737
738
739 int32_t
ud_read_icb_till_off(struct ud_inode * ip,u_offset_t offset)740 ud_read_icb_till_off(struct ud_inode *ip, u_offset_t offset)
741 {
742 int32_t error = 0;
743 struct icb_ext *iext;
744
745 ud_printf("ud_read_icb_till_off\n");
746
747 if (ip->i_desc_type == ICB_FLAG_ONE_AD)
748 return (0);
749 else if ((ip->i_astrat != STRAT_TYPE4) &&
750 (ip->i_astrat != STRAT_TYPE4096))
751 return (EINVAL);
752 else if (ip->i_ext_used == 0)
753 return ((ip->i_size == 0) ? 0 : EINVAL);
754
755 /*
756 * supported allocation strategies are
757 * STRAT_TYPE4 and STRAT_TYPE4096
758 */
759
760 mutex_enter(&ip->i_con_lock);
761 iext = &ip->i_ext[ip->i_ext_used - 1];
762 while ((iext->ib_offset + iext->ib_count) < offset) {
763 if (ip->i_con_used == ip->i_con_read) {
764 error = EINVAL;
765 break;
766 }
767 if (error = ud_read_next_cont(ip))
768 break;
769 ip->i_con_read++;
770 iext = &ip->i_ext[ip->i_ext_used - 1];
771 }
772 mutex_exit(&ip->i_con_lock);
773
774 return (error);
775 }
776
777
778 /*
779 * Assumption is the off is beyond ip->i_size
780 * And we will have atleast one ext used
781 */
782 int32_t
ud_last_alloc_ext(struct ud_inode * ip,uint64_t off,uint32_t size,int32_t alloc_only)783 ud_last_alloc_ext(struct ud_inode *ip, uint64_t off,
784 uint32_t size, int32_t alloc_only)
785 {
786 struct icb_ext *iext;
787 struct udf_vfs *udf_vfsp;
788 int32_t lbsize, lbmask;
789 uint64_t end_req, end_count, icb_offset;
790 uint64_t count;
791 int32_t error = 0;
792
793
794 udf_vfsp = ip->i_udf;
795 lbsize = udf_vfsp->udf_lbsize;
796 lbmask = udf_vfsp->udf_lbmask;
797
798 end_req = BASE(off) + size;
799
800
801 /*
802 * If we are here it means the file
803 * is growing beyond the end of the
804 * current block. So round up the
805 * last extent
806 */
807
808 iext = &ip->i_ext[ip->i_ext_used - 1];
809 iext->ib_count = CEIL(iext->ib_count);
810
811 /*
812 * Figure out if we can create
813 * a hole here
814 */
815
816
817 end_count = iext->ib_offset + iext->ib_count;
818
819 if ((PCEIL(end_count) < PBASE(off)) &&
820 ((PBASE(off) - PCEIL(end_count)) >= PAGESIZE)) {
821
822 count = PCEIL(end_count) - CEIL(end_count);
823 if (count >= lbsize) {
824
825 /*
826 * There is space between the begining
827 * of the hole to be created and
828 * end of the last offset
829 * Allocate blocks for it
830 */
831
832 iext = &ip->i_ext[ip->i_ext_used - 1];
833 icb_offset = iext->ib_offset + CEIL(iext->ib_count);
834
835 if (iext->ib_flags == IB_UN_RE_AL) {
836
837 /*
838 * Previous extent is a unallocated
839 * extent. Create a new allocated
840 * extent
841 */
842
843 error = ud_create_ext(ip, ip->i_ext_used,
844 ALLOC_SPACE | NEW_EXT,
845 alloc_only, icb_offset, &count);
846
847 } else {
848
849 /*
850 * Last extent is allocated
851 * try to allocate adjascent to the
852 * last extent
853 */
854
855 error = ud_create_ext(ip, ip->i_ext_used - 1,
856 ALLOC_SPACE, alloc_only,
857 icb_offset, &count);
858 }
859
860 if (error != 0) {
861 return (error);
862 }
863 }
864
865 iext = &ip->i_ext[ip->i_ext_used - 1];
866 end_count = iext->ib_offset + iext->ib_count;
867 count = PBASE(off) - PCEIL(end_count);
868 icb_offset = PCEIL(end_count);
869
870 if (iext->ib_flags == IB_UN_RE_AL) {
871
872 /*
873 * The last extent is unallocated
874 * Just bump the extent count
875 */
876 (void) ud_create_ext(ip, ip->i_ext_used - 1,
877 0, alloc_only, icb_offset, &count);
878 } else {
879
880 /*
881 * Last extent is allocated
882 * round up the size of the extent to
883 * lbsize and allocate a new unallocated extent
884 */
885 iext->ib_count = CEIL(iext->ib_count);
886 (void) ud_create_ext(ip, ip->i_ext_used,
887 NEW_EXT, alloc_only, icb_offset, &count);
888 }
889
890 icb_offset = PBASE(off);
891 } else {
892
893 /*
894 * We cannot create any hole inbetween
895 * the last extent and the off so
896 * round up the count in the last extent
897 */
898
899 iext = &ip->i_ext[ip->i_ext_used - 1];
900 iext->ib_count = CEIL(iext->ib_count);
901
902 }
903
904
905 iext = &ip->i_ext[ip->i_ext_used - 1];
906 count = end_req - (iext->ib_offset + iext->ib_count);
907 icb_offset = iext->ib_offset + CEIL(iext->ib_count);
908
909 if (iext->ib_flags == IB_UN_RE_AL) {
910
911 /*
912 * Last extent was a unallocated extent
913 * create a new extent
914 */
915
916 error = ud_create_ext(ip, ip->i_ext_used,
917 ALLOC_SPACE | NEW_EXT, alloc_only, icb_offset, &count);
918 } else {
919
920 /*
921 * Last extent was an allocated extent
922 * try to allocate adjascent to the old blocks
923 */
924
925 error = ud_create_ext(ip, ip->i_ext_used - 1,
926 ALLOC_SPACE, alloc_only, icb_offset, &count);
927 }
928
929 return (error);
930 }
931
932 /*
933 * Break up the icb_ext at index
934 * into two icb_ext,
935 * one at index ib_count "count" and
936 * the other at index+1 with ib_count = old_ib_count - count
937 */
938 int32_t
ud_break_create_new_icb(struct ud_inode * ip,int32_t index,uint32_t count)939 ud_break_create_new_icb(struct ud_inode *ip,
940 int32_t index, uint32_t count)
941 {
942 int32_t i, error;
943 struct icb_ext *iext, *next;
944
945
946 ud_printf("ud_break_create_new_icb\n");
947 iext = &ip->i_ext[index];
948
949 ASSERT(count < iext->ib_count);
950
951 if ((error = ud_bump_ext_count(ip, KM_SLEEP)) != 0) {
952 return (error);
953 }
954
955 for (i = ip->i_ext_used; i > index; i--) {
956 ip->i_ext[i] = ip->i_ext[i - 1];
957 }
958
959 next = &ip->i_ext[index + 1];
960 iext = &ip->i_ext[index];
961
962 iext->ib_count = count;
963 next->ib_count -= count;
964 next->ib_offset = iext->ib_offset + iext->ib_count;
965 if (iext->ib_flags != IB_UN_RE_AL) {
966 next->ib_block = iext->ib_block +
967 iext->ib_count >> ip->i_udf->udf_l2b_shift;
968 }
969 ip->i_ext_used++;
970 return (0);
971 }
972
973 void
ud_remove_ext_at_index(struct ud_inode * ip,int32_t index)974 ud_remove_ext_at_index(struct ud_inode *ip, int32_t index)
975 {
976 int32_t i;
977
978 ASSERT(index <= ip->i_ext_used);
979
980 for (i = index; i < ip->i_ext_used; i++) {
981 if ((i + 1) < ip->i_ext_count) {
982 ip->i_ext[i] = ip->i_ext[i + 1];
983 } else {
984 bzero(&ip->i_ext[i], sizeof (struct icb_ext));
985 }
986 }
987 ip->i_ext_used --;
988 }
989
990 int32_t
ud_bump_ext_count(struct ud_inode * ip,int32_t sleep_flag)991 ud_bump_ext_count(struct ud_inode *ip, int32_t sleep_flag)
992 {
993 int32_t error = 0;
994 struct icb_ext *iext;
995 uint32_t old_count, elen;
996
997 ASSERT(ip);
998 ASSERT(sleep_flag == KM_SLEEP);
999
1000 ud_printf("ud_bump_ext_count\n");
1001
1002 if (ip->i_ext_used >= ip->i_ext_count) {
1003
1004 old_count = sizeof (struct icb_ext) * ip->i_ext_count;
1005 ip->i_ext_count += EXT_PER_MALLOC;
1006 iext = kmem_zalloc(sizeof (struct icb_ext) *
1007 ip->i_ext_count, sleep_flag);
1008 bcopy(ip->i_ext, iext, old_count);
1009 kmem_free(ip->i_ext, old_count);
1010 ip->i_ext = iext;
1011 }
1012
1013 if (ip->i_ext_used >= ip->i_cur_max_ext) {
1014 int32_t prox;
1015 struct icb_ext *icon;
1016 uint32_t blkno, sz;
1017 int32_t lbmask, l2b;
1018
1019 lbmask = ip->i_udf->udf_lbmask;
1020 l2b = ip->i_udf->udf_l2b_shift;
1021
1022 if ((error = ud_read_icb_till_off(ip, ip->i_size)) != 0) {
1023 return (error);
1024 }
1025
1026 /*
1027 * If there are any old cont extents
1028 * allocate the new one ajscant to the old one
1029 */
1030 if (ip->i_con_used != 0) {
1031 icon = &ip->i_con[ip->i_con_used - 1];
1032 prox = icon->ib_block + (CEIL(icon->ib_count) >> l2b);
1033 } else {
1034 prox = 0;
1035 }
1036
1037 /*
1038 * Allocate space
1039 */
1040 if ((error = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1041 prox, 1, &blkno, &sz, 0, 0)) != 0) {
1042 return (error);
1043 }
1044 if (sz == 0) {
1045 return (ENOSPC);
1046 }
1047
1048 sz <<= l2b;
1049
1050 if (ip->i_con_used == ip->i_con_count) {
1051 struct icb_ext *old;
1052 int32_t old_count;
1053
1054 old = ip->i_con;
1055 old_count = ip->i_con_count *
1056 sizeof (struct icb_ext);
1057 ip->i_con_count += EXT_PER_MALLOC;
1058 ip->i_con = kmem_zalloc(ip->i_con_count *
1059 sizeof (struct icb_ext), KM_SLEEP);
1060 if (old != 0) {
1061 bcopy(old, ip->i_con, old_count);
1062 kmem_free(old, old_count);
1063 }
1064 }
1065 icon = &ip->i_con[ip->i_con_used++];
1066 icon->ib_flags = IB_CON;
1067 icon->ib_prn = ip->i_icb_prn;
1068 icon->ib_block = blkno;
1069 icon->ib_count = sz;
1070 icon->ib_offset = 0;
1071 icon->ib_marker1 = (uint32_t)0xAAAAAAAA;
1072 icon->ib_marker2 = (uint32_t)0xBBBBBBBB;
1073
1074 /*
1075 * Bump the i_cur_max_ext according to
1076 * the space allocated
1077 */
1078 if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
1079 elen = sizeof (struct short_ad);
1080 } else if (ip->i_desc_type == ICB_FLAG_LONG_AD) {
1081 elen = sizeof (struct long_ad);
1082 } else {
1083 return (ENOSPC);
1084 }
1085 sz = sz - (sizeof (struct alloc_ext_desc) + elen);
1086 ip->i_cur_max_ext += sz / elen;
1087 }
1088 return (error);
1089 }
1090
1091 int32_t
ud_create_ext(struct ud_inode * ip,int32_t index,uint32_t flags,int32_t alloc_only,uint64_t offset,uint64_t * count)1092 ud_create_ext(struct ud_inode *ip, int32_t index, uint32_t flags,
1093 int32_t alloc_only, uint64_t offset, uint64_t *count)
1094 {
1095 struct icb_ext *iext, *pext;
1096 struct udf_vfs *udf_vfsp;
1097 int32_t error = 0, blkcount, acount;
1098 uint32_t blkno, sz, prox, mext_sz;
1099 int32_t lbmask, l2b;
1100
1101 if (*count == 0) {
1102 return (0);
1103 }
1104
1105 begin:
1106 udf_vfsp = ip->i_udf;
1107 lbmask = udf_vfsp->udf_lbmask;
1108 l2b = udf_vfsp->udf_l2b_shift;
1109 mext_sz = (1 << MEXT_BITS) - PAGESIZE;
1110
1111 if ((error = ud_bump_ext_count(ip, KM_SLEEP)) != 0) {
1112 return (error);
1113 }
1114
1115 iext = &ip->i_ext[index];
1116 if (flags & ALLOC_SPACE) {
1117 if ((flags & NEW_EXT) ||
1118 (ip->i_ext_count == 0)) {
1119
1120 iext->ib_flags = 0;
1121 iext->ib_prn = ip->i_icb_prn;
1122 if (*count > mext_sz) {
1123 blkcount = mext_sz >> l2b;
1124 } else {
1125 blkcount = CEIL(*count) >> l2b;
1126 }
1127 if ((error = ud_alloc_space(ip->i_vfs,
1128 ip->i_icb_prn, 0, blkcount,
1129 &blkno, &sz, 1, 0)) != 0) {
1130 return (error);
1131 }
1132 if (sz == 0) {
1133 return (ENOSPC);
1134 }
1135 ip->i_lbr += sz;
1136 iext->ib_block = blkno;
1137 acount = sz << l2b;
1138 if ((sz << l2b) > *count) {
1139 iext->ib_count = *count;
1140 *count = 0;
1141 } else {
1142 iext->ib_count = sz << l2b;
1143 *count -= iext->ib_count;
1144 }
1145 iext->ib_offset = offset;
1146 if (ip->i_ext_used <= index)
1147 ip->i_ext_used ++;
1148 } else {
1149 if ((iext->ib_count + *count) > mext_sz) {
1150 blkcount = (mext_sz - iext->ib_count) >> l2b;
1151 } else {
1152 blkcount = CEIL(*count) >> l2b;
1153 }
1154 if (blkcount == 0) {
1155 flags |= NEW_EXT;
1156 index++;
1157 goto begin;
1158 }
1159 prox = iext->ib_block + (CEIL(iext->ib_count) >> l2b);
1160 if ((error = ud_alloc_space(ip->i_vfs,
1161 ip->i_icb_prn, prox, blkcount,
1162 &blkno, &sz, 1, 0)) != 0) {
1163 return (error);
1164 }
1165 if (sz == 0) {
1166 return (ENOSPC);
1167 }
1168 acount = sz << l2b;
1169 if (acount > *count) {
1170 acount = *count;
1171 *count = 0;
1172 } else {
1173 *count -= acount;
1174 }
1175 ip->i_lbr += sz;
1176 if (prox == blkno) {
1177 iext->ib_count += acount;
1178 } else {
1179 if ((error = ud_bump_ext_count(ip, KM_SLEEP))
1180 != 0) {
1181 return (error);
1182 }
1183 pext = &ip->i_ext[index];
1184 iext = &ip->i_ext[index + 1];
1185 iext->ib_flags = 0;
1186 iext->ib_prn = ip->i_icb_prn;
1187 iext->ib_block = blkno;
1188 iext->ib_offset =
1189 pext->ib_offset + pext->ib_count;
1190 iext->ib_count = acount;
1191 /*
1192 * Increment the index, since we have used
1193 * the extent at [index+1] above.
1194 */
1195 index++;
1196 if (ip->i_ext_used <= index)
1197 ip->i_ext_used ++;
1198 }
1199 }
1200 if (alloc_only == 0) {
1201 error = ud_zero_it(ip, blkno, sz);
1202 }
1203 if (*count) {
1204 offset = iext->ib_offset + CEIL(iext->ib_count);
1205 flags |= NEW_EXT;
1206 index++;
1207 goto begin;
1208 }
1209 } else {
1210 if (flags & NEW_EXT) {
1211 iext->ib_flags = IB_UN_RE_AL;
1212 iext->ib_prn = 0;
1213 iext->ib_block = 0;
1214 if (*count > mext_sz) {
1215 iext->ib_count = mext_sz;
1216 *count -= iext->ib_count;
1217 } else {
1218 iext->ib_count = *count;
1219 *count = 0;
1220 }
1221 iext->ib_offset = offset;
1222 if (ip->i_ext_used <= index)
1223 ip->i_ext_used ++;
1224 } else {
1225 ASSERT(iext->ib_flags == IB_UN_RE_AL);
1226 if ((iext->ib_count + *count) > mext_sz) {
1227 acount = mext_sz - iext->ib_count;
1228 iext->ib_count += acount;
1229 *count -= acount;
1230 } else {
1231 iext->ib_count += *count;
1232 *count = 0;
1233 }
1234 }
1235 if (*count != 0) {
1236 offset = iext->ib_offset + CEIL(iext->ib_count);
1237 flags |= NEW_EXT;
1238 index++;
1239 goto begin;
1240 }
1241 }
1242 iext->ib_marker1 = (uint32_t)0xAAAAAAAA;
1243 iext->ib_marker2 = (uint32_t)0xBBBBBBBB;
1244 return (error);
1245 }
1246
1247 #undef CEIL
1248 #undef BASE
1249
1250 int32_t
ud_zero_it(struct ud_inode * ip,uint32_t start_block,uint32_t block_count)1251 ud_zero_it(struct ud_inode *ip, uint32_t start_block, uint32_t block_count)
1252 {
1253 struct udf_vfs *udf_vfsp;
1254 uint32_t bno, dummy;
1255 int32_t error;
1256 struct buf *bp;
1257
1258 /*
1259 * Donot use bio routines
1260 * since the buffer can sit
1261 * long enough in cache for the space
1262 * to be allocated/freed and
1263 * then allocated
1264 */
1265 udf_vfsp = ip->i_udf;
1266 bno = ud_xlate_to_daddr(udf_vfsp,
1267 ip->i_icb_prn, start_block, block_count, &dummy);
1268
1269 dummy = block_count << udf_vfsp->udf_l2b_shift;
1270 bp = (struct buf *)kmem_zalloc(biosize(), KM_SLEEP);
1271 sema_init(&bp->b_sem, 0, NULL, SEMA_DEFAULT, NULL);
1272 sema_init(&bp->b_io, 0, NULL, SEMA_DEFAULT, NULL);
1273
1274 bp->b_flags = B_WRITE | B_BUSY;
1275 bp->b_edev = ip->i_dev;
1276 bp->b_dev = cmpdev(ip->i_dev);
1277 bp->b_blkno = bno << udf_vfsp->udf_l2d_shift;
1278 bp->b_bcount = dummy;
1279 bp->b_un.b_addr = kmem_zalloc(bp->b_bcount, KM_SLEEP);
1280 bp->b_file = ip->i_vnode;
1281 bp->b_offset = -1;
1282
1283 (void) bdev_strategy(bp);
1284 if (error = biowait(bp)) {
1285 cmn_err(CE_WARN, "error in write\n");
1286 }
1287
1288 kmem_free(bp->b_un.b_addr, dummy);
1289 sema_destroy(&bp->b_io);
1290 sema_destroy(&bp->b_sem);
1291 kmem_free((caddr_t)bp, biosize());
1292
1293 return (error);
1294 }
1295