1
2
3
4
5
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_mount.h"
13#include "xfs_inode.h"
14#include "xfs_trans.h"
15#include "xfs_dir2.h"
16#include "xfs_dir2_priv.h"
17#include "xfs_trace.h"
18
19
20
21
22static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
23 xfs_dir2_sf_entry_t *sfep,
24 xfs_dir2_data_aoff_t offset,
25 int new_isize);
26static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
27 int new_isize);
28static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
29 xfs_dir2_sf_entry_t **sfepp,
30 xfs_dir2_data_aoff_t *offsetp);
31#ifdef DEBUG
32static void xfs_dir2_sf_check(xfs_da_args_t *args);
33#else
34#define xfs_dir2_sf_check(args)
35#endif
36
37static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
38static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
39
40int
41xfs_dir2_sf_entsize(
42 struct xfs_mount *mp,
43 struct xfs_dir2_sf_hdr *hdr,
44 int len)
45{
46 int count = len;
47
48 count += sizeof(struct xfs_dir2_sf_entry);
49 count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE;
50
51 if (xfs_sb_version_hasftype(&mp->m_sb))
52 count += sizeof(uint8_t);
53 return count;
54}
55
56struct xfs_dir2_sf_entry *
57xfs_dir2_sf_nextentry(
58 struct xfs_mount *mp,
59 struct xfs_dir2_sf_hdr *hdr,
60 struct xfs_dir2_sf_entry *sfep)
61{
62 return (void *)sfep + xfs_dir2_sf_entsize(mp, hdr, sfep->namelen);
63}
64
65
66
67
68
69
70
71xfs_ino_t
72xfs_dir2_sf_get_ino(
73 struct xfs_mount *mp,
74 struct xfs_dir2_sf_hdr *hdr,
75 struct xfs_dir2_sf_entry *sfep)
76{
77 uint8_t *from = sfep->name + sfep->namelen;
78
79 if (xfs_sb_version_hasftype(&mp->m_sb))
80 from++;
81
82 if (!hdr->i8count)
83 return get_unaligned_be32(from);
84 return get_unaligned_be64(from) & XFS_MAXINUMBER;
85}
86
87void
88xfs_dir2_sf_put_ino(
89 struct xfs_mount *mp,
90 struct xfs_dir2_sf_hdr *hdr,
91 struct xfs_dir2_sf_entry *sfep,
92 xfs_ino_t ino)
93{
94 uint8_t *to = sfep->name + sfep->namelen;
95
96 ASSERT(ino <= XFS_MAXINUMBER);
97
98 if (xfs_sb_version_hasftype(&mp->m_sb))
99 to++;
100
101 if (hdr->i8count)
102 put_unaligned_be64(ino, to);
103 else
104 put_unaligned_be32(ino, to);
105}
106
107xfs_ino_t
108xfs_dir2_sf_get_parent_ino(
109 struct xfs_dir2_sf_hdr *hdr)
110{
111 if (!hdr->i8count)
112 return get_unaligned_be32(hdr->parent);
113 return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
114}
115
116void
117xfs_dir2_sf_put_parent_ino(
118 struct xfs_dir2_sf_hdr *hdr,
119 xfs_ino_t ino)
120{
121 ASSERT(ino <= XFS_MAXINUMBER);
122
123 if (hdr->i8count)
124 put_unaligned_be64(ino, hdr->parent);
125 else
126 put_unaligned_be32(ino, hdr->parent);
127}
128
129
130
131
132
133uint8_t
134xfs_dir2_sf_get_ftype(
135 struct xfs_mount *mp,
136 struct xfs_dir2_sf_entry *sfep)
137{
138 if (xfs_sb_version_hasftype(&mp->m_sb)) {
139 uint8_t ftype = sfep->name[sfep->namelen];
140
141 if (ftype < XFS_DIR3_FT_MAX)
142 return ftype;
143 }
144
145 return XFS_DIR3_FT_UNKNOWN;
146}
147
148void
149xfs_dir2_sf_put_ftype(
150 struct xfs_mount *mp,
151 struct xfs_dir2_sf_entry *sfep,
152 uint8_t ftype)
153{
154 ASSERT(ftype < XFS_DIR3_FT_MAX);
155
156 if (xfs_sb_version_hasftype(&mp->m_sb))
157 sfep->name[sfep->namelen] = ftype;
158}
159
160
161
162
163
164
165
166int
167xfs_dir2_block_sfsize(
168 xfs_inode_t *dp,
169 xfs_dir2_data_hdr_t *hdr,
170 xfs_dir2_sf_hdr_t *sfhp)
171{
172 xfs_dir2_dataptr_t addr;
173 xfs_dir2_leaf_entry_t *blp;
174 xfs_dir2_block_tail_t *btp;
175 int count;
176 xfs_dir2_data_entry_t *dep;
177 int i;
178 int i8count;
179 int isdot;
180 int isdotdot;
181 xfs_mount_t *mp;
182 int namelen;
183 xfs_ino_t parent = 0;
184 int size=0;
185 int has_ftype;
186 struct xfs_da_geometry *geo;
187
188 mp = dp->i_mount;
189 geo = mp->m_dir_geo;
190
191
192
193
194
195 has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
196
197 count = i8count = namelen = 0;
198 btp = xfs_dir2_block_tail_p(geo, hdr);
199 blp = xfs_dir2_block_leaf_p(btp);
200
201
202
203
204 for (i = 0; i < be32_to_cpu(btp->count); i++) {
205 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
206 continue;
207
208
209
210 dep = (xfs_dir2_data_entry_t *)((char *)hdr +
211 xfs_dir2_dataptr_to_off(geo, addr));
212
213
214
215
216
217 isdot = dep->namelen == 1 && dep->name[0] == '.';
218 isdotdot =
219 dep->namelen == 2 &&
220 dep->name[0] == '.' && dep->name[1] == '.';
221
222 if (!isdot)
223 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
224
225
226 if (!isdot && !isdotdot) {
227 count++;
228 namelen += dep->namelen + has_ftype;
229 } else if (isdotdot)
230 parent = be64_to_cpu(dep->inumber);
231
232
233
234 size = xfs_dir2_sf_hdr_size(i8count) +
235 count * 3 * sizeof(u8) +
236 namelen +
237 (i8count ?
238 count * XFS_INO64_SIZE :
239 count * XFS_INO32_SIZE);
240 if (size > XFS_IFORK_DSIZE(dp))
241 return size;
242 }
243
244
245
246 sfhp->count = count;
247 sfhp->i8count = i8count;
248 xfs_dir2_sf_put_parent_ino(sfhp, parent);
249 return size;
250}
251
252
253
254
255
256int
257xfs_dir2_block_to_sf(
258 struct xfs_da_args *args,
259 struct xfs_buf *bp,
260 int size,
261 struct xfs_dir2_sf_hdr *sfhp)
262{
263 struct xfs_inode *dp = args->dp;
264 struct xfs_mount *mp = dp->i_mount;
265 int error;
266 int logflags;
267 struct xfs_dir2_sf_entry *sfep;
268 struct xfs_dir2_sf_hdr *sfp;
269 unsigned int offset = args->geo->data_entry_offset;
270 unsigned int end;
271
272 trace_xfs_dir2_block_to_sf(args);
273
274
275
276
277
278
279 sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
280 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
281
282
283
284
285
286 end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
287 sfep = xfs_dir2_sf_firstentry(sfp);
288 while (offset < end) {
289 struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
290 struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
291
292
293
294
295 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
296 offset += be16_to_cpu(dup->length);
297 continue;
298 }
299
300
301
302
303 if (dep->namelen == 1 && dep->name[0] == '.')
304 ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
305
306
307
308 else if (dep->namelen == 2 &&
309 dep->name[0] == '.' && dep->name[1] == '.')
310 ASSERT(be64_to_cpu(dep->inumber) ==
311 xfs_dir2_sf_get_parent_ino(sfp));
312
313
314
315 else {
316 sfep->namelen = dep->namelen;
317 xfs_dir2_sf_put_offset(sfep, offset);
318 memcpy(sfep->name, dep->name, dep->namelen);
319 xfs_dir2_sf_put_ino(mp, sfp, sfep,
320 be64_to_cpu(dep->inumber));
321 xfs_dir2_sf_put_ftype(mp, sfep,
322 xfs_dir2_data_get_ftype(mp, dep));
323
324 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
325 }
326 offset += xfs_dir2_data_entsize(mp, dep->namelen);
327 }
328 ASSERT((char *)sfep - (char *)sfp == size);
329
330
331 logflags = XFS_ILOG_CORE;
332 error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
333 if (error) {
334 ASSERT(error != -ENOSPC);
335 goto out;
336 }
337
338
339
340
341
342
343
344 ASSERT(dp->i_df.if_bytes == 0);
345 xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
346 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
347 dp->i_d.di_size = size;
348
349 logflags |= XFS_ILOG_DDATA;
350 xfs_dir2_sf_check(args);
351out:
352 xfs_trans_log_inode(args->trans, dp, logflags);
353 kmem_free(sfp);
354 return error;
355}
356
357
358
359
360
361
362
363int
364xfs_dir2_sf_addname(
365 xfs_da_args_t *args)
366{
367 xfs_inode_t *dp;
368 int error;
369 int incr_isize;
370 int new_isize;
371 int objchange;
372 xfs_dir2_data_aoff_t offset = 0;
373 int pick;
374 xfs_dir2_sf_hdr_t *sfp;
375 xfs_dir2_sf_entry_t *sfep = NULL;
376
377 trace_xfs_dir2_sf_addname(args);
378
379 ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
380 dp = args->dp;
381 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
382 ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
383 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
384 ASSERT(dp->i_df.if_u1.if_data != NULL);
385 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
386 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
387
388
389
390 incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
391 objchange = 0;
392
393
394
395
396 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
397
398
399
400 incr_isize += (sfp->count + 2) * XFS_INO64_DIFF;
401 objchange = 1;
402 }
403
404 new_isize = (int)dp->i_d.di_size + incr_isize;
405
406
407
408
409 if (new_isize > XFS_IFORK_DSIZE(dp) ||
410 (pick =
411 xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
412
413
414
415 if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
416 return -ENOSPC;
417
418
419
420 error = xfs_dir2_sf_to_block(args);
421 if (error)
422 return error;
423 return xfs_dir2_block_addname(args);
424 }
425
426
427
428 if (args->op_flags & XFS_DA_OP_JUSTCHECK)
429 return 0;
430
431
432
433 if (pick == 1)
434 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
435
436
437
438
439 else {
440 ASSERT(pick == 2);
441 if (objchange)
442 xfs_dir2_sf_toino8(args);
443 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
444 }
445 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
446 return 0;
447}
448
449
450
451
452
453
454
455
456static void
457xfs_dir2_sf_addname_easy(
458 xfs_da_args_t *args,
459 xfs_dir2_sf_entry_t *sfep,
460 xfs_dir2_data_aoff_t offset,
461 int new_isize)
462{
463 struct xfs_inode *dp = args->dp;
464 struct xfs_mount *mp = dp->i_mount;
465 int byteoff;
466 xfs_dir2_sf_hdr_t *sfp;
467
468 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
469 byteoff = (int)((char *)sfep - (char *)sfp);
470
471
472
473 xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
474 XFS_DATA_FORK);
475
476
477
478 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
479 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
480
481
482
483 sfep->namelen = args->namelen;
484 xfs_dir2_sf_put_offset(sfep, offset);
485 memcpy(sfep->name, args->name, sfep->namelen);
486 xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
487 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
488
489
490
491
492 sfp->count++;
493 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
494 sfp->i8count++;
495 dp->i_d.di_size = new_isize;
496 xfs_dir2_sf_check(args);
497}
498
499
500
501
502
503
504
505
506
507
508static void
509xfs_dir2_sf_addname_hard(
510 xfs_da_args_t *args,
511 int objchange,
512 int new_isize)
513{
514 struct xfs_inode *dp = args->dp;
515 struct xfs_mount *mp = dp->i_mount;
516 int add_datasize;
517 char *buf;
518 int eof;
519 int nbytes;
520 xfs_dir2_data_aoff_t new_offset;
521 xfs_dir2_data_aoff_t offset;
522 int old_isize;
523 xfs_dir2_sf_entry_t *oldsfep;
524 xfs_dir2_sf_hdr_t *oldsfp;
525 xfs_dir2_sf_entry_t *sfep;
526 xfs_dir2_sf_hdr_t *sfp;
527
528
529
530
531 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
532 old_isize = (int)dp->i_d.di_size;
533 buf = kmem_alloc(old_isize, 0);
534 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
535 memcpy(oldsfp, sfp, old_isize);
536
537
538
539
540
541 for (offset = args->geo->data_first_offset,
542 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
543 add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
544 eof = (char *)oldsfep == &buf[old_isize];
545 !eof;
546 offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
547 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
548 eof = (char *)oldsfep == &buf[old_isize]) {
549 new_offset = xfs_dir2_sf_get_offset(oldsfep);
550 if (offset + add_datasize <= new_offset)
551 break;
552 }
553
554
555
556
557
558 xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
559 xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
560
561
562
563 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
564
565
566
567 nbytes = (int)((char *)oldsfep - (char *)oldsfp);
568 memcpy(sfp, oldsfp, nbytes);
569 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
570
571
572
573 sfep->namelen = args->namelen;
574 xfs_dir2_sf_put_offset(sfep, offset);
575 memcpy(sfep->name, args->name, sfep->namelen);
576 xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
577 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
578 sfp->count++;
579 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
580 sfp->i8count++;
581
582
583
584 if (!eof) {
585 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
586 memcpy(sfep, oldsfep, old_isize - nbytes);
587 }
588 kmem_free(buf);
589 dp->i_d.di_size = new_isize;
590 xfs_dir2_sf_check(args);
591}
592
593
594
595
596
597
598
599
600static int
601xfs_dir2_sf_addname_pick(
602 xfs_da_args_t *args,
603 int objchange,
604 xfs_dir2_sf_entry_t **sfepp,
605 xfs_dir2_data_aoff_t *offsetp)
606{
607 struct xfs_inode *dp = args->dp;
608 struct xfs_mount *mp = dp->i_mount;
609 int holefit;
610 int i;
611 xfs_dir2_data_aoff_t offset;
612 xfs_dir2_sf_entry_t *sfep;
613 xfs_dir2_sf_hdr_t *sfp;
614 int size;
615 int used;
616
617 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
618 size = xfs_dir2_data_entsize(mp, args->namelen);
619 offset = args->geo->data_first_offset;
620 sfep = xfs_dir2_sf_firstentry(sfp);
621 holefit = 0;
622
623
624
625
626
627 for (i = 0; i < sfp->count; i++) {
628 if (!holefit)
629 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
630 offset = xfs_dir2_sf_get_offset(sfep) +
631 xfs_dir2_data_entsize(mp, sfep->namelen);
632 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
633 }
634
635
636
637
638 used = offset +
639 (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
640 (uint)sizeof(xfs_dir2_block_tail_t);
641
642
643
644
645
646 if (used + (holefit ? 0 : size) > args->geo->blksize)
647 return 0;
648
649
650
651 if (objchange)
652 return 2;
653
654
655
656 if (used + size > args->geo->blksize)
657 return 2;
658
659
660
661 *sfepp = sfep;
662 *offsetp = offset;
663 return 1;
664}
665
666#ifdef DEBUG
667
668
669
670static void
671xfs_dir2_sf_check(
672 xfs_da_args_t *args)
673{
674 struct xfs_inode *dp = args->dp;
675 struct xfs_mount *mp = dp->i_mount;
676 int i;
677 int i8count;
678 xfs_ino_t ino;
679 int offset;
680 xfs_dir2_sf_entry_t *sfep;
681 xfs_dir2_sf_hdr_t *sfp;
682
683 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
684 offset = args->geo->data_first_offset;
685 ino = xfs_dir2_sf_get_parent_ino(sfp);
686 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
687
688 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
689 i < sfp->count;
690 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
691 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
692 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
693 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
694 offset =
695 xfs_dir2_sf_get_offset(sfep) +
696 xfs_dir2_data_entsize(mp, sfep->namelen);
697 ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
698 }
699 ASSERT(i8count == sfp->i8count);
700 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
701 ASSERT(offset +
702 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
703 (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize);
704}
705#endif
706
707
708xfs_failaddr_t
709xfs_dir2_sf_verify(
710 struct xfs_inode *ip)
711{
712 struct xfs_mount *mp = ip->i_mount;
713 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
714 struct xfs_dir2_sf_hdr *sfp;
715 struct xfs_dir2_sf_entry *sfep;
716 struct xfs_dir2_sf_entry *next_sfep;
717 char *endp;
718 xfs_ino_t ino;
719 int i;
720 int i8count;
721 int offset;
722 int64_t size;
723 int error;
724 uint8_t filetype;
725
726 ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
727
728 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
729 size = ifp->if_bytes;
730
731
732
733
734 if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
735 size < xfs_dir2_sf_hdr_size(sfp->i8count))
736 return __this_address;
737
738 endp = (char *)sfp + size;
739
740
741 ino = xfs_dir2_sf_get_parent_ino(sfp);
742 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
743 error = xfs_dir_ino_validate(mp, ino);
744 if (error)
745 return __this_address;
746 offset = mp->m_dir_geo->data_first_offset;
747
748
749 sfep = xfs_dir2_sf_firstentry(sfp);
750 for (i = 0; i < sfp->count; i++) {
751
752
753
754
755
756 if (((char *)sfep + sizeof(*sfep)) >= endp)
757 return __this_address;
758
759
760 if (sfep->namelen == 0)
761 return __this_address;
762
763
764
765
766
767
768 next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
769 if (endp < (char *)next_sfep)
770 return __this_address;
771
772
773 if (xfs_dir2_sf_get_offset(sfep) < offset)
774 return __this_address;
775
776
777 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
778 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
779 error = xfs_dir_ino_validate(mp, ino);
780 if (error)
781 return __this_address;
782
783
784 filetype = xfs_dir2_sf_get_ftype(mp, sfep);
785 if (filetype >= XFS_DIR3_FT_MAX)
786 return __this_address;
787
788 offset = xfs_dir2_sf_get_offset(sfep) +
789 xfs_dir2_data_entsize(mp, sfep->namelen);
790
791 sfep = next_sfep;
792 }
793 if (i8count != sfp->i8count)
794 return __this_address;
795 if ((void *)sfep != (void *)endp)
796 return __this_address;
797
798
799 if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
800 (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
801 return __this_address;
802
803 return NULL;
804}
805
806
807
808
809int
810xfs_dir2_sf_create(
811 xfs_da_args_t *args,
812 xfs_ino_t pino)
813{
814 xfs_inode_t *dp;
815 int i8count;
816 xfs_dir2_sf_hdr_t *sfp;
817 int size;
818
819 trace_xfs_dir2_sf_create(args);
820
821 dp = args->dp;
822
823 ASSERT(dp != NULL);
824 ASSERT(dp->i_d.di_size == 0);
825
826
827
828
829 if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
830 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
831 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
832 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
833 dp->i_df.if_flags |= XFS_IFINLINE;
834 }
835 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
836 ASSERT(dp->i_df.if_bytes == 0);
837 i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
838 size = xfs_dir2_sf_hdr_size(i8count);
839
840
841
842 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
843
844
845
846 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
847 sfp->i8count = i8count;
848
849
850
851 xfs_dir2_sf_put_parent_ino(sfp, pino);
852 sfp->count = 0;
853 dp->i_d.di_size = size;
854 xfs_dir2_sf_check(args);
855 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
856 return 0;
857}
858
859
860
861
862
863int
864xfs_dir2_sf_lookup(
865 xfs_da_args_t *args)
866{
867 struct xfs_inode *dp = args->dp;
868 struct xfs_mount *mp = dp->i_mount;
869 int i;
870 int error;
871 xfs_dir2_sf_entry_t *sfep;
872 xfs_dir2_sf_hdr_t *sfp;
873 enum xfs_dacmp cmp;
874 xfs_dir2_sf_entry_t *ci_sfep;
875
876 trace_xfs_dir2_sf_lookup(args);
877
878 xfs_dir2_sf_check(args);
879
880 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
881 ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
882 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
883 ASSERT(dp->i_df.if_u1.if_data != NULL);
884 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
885 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
886
887
888
889 if (args->namelen == 1 && args->name[0] == '.') {
890 args->inumber = dp->i_ino;
891 args->cmpresult = XFS_CMP_EXACT;
892 args->filetype = XFS_DIR3_FT_DIR;
893 return -EEXIST;
894 }
895
896
897
898 if (args->namelen == 2 &&
899 args->name[0] == '.' && args->name[1] == '.') {
900 args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
901 args->cmpresult = XFS_CMP_EXACT;
902 args->filetype = XFS_DIR3_FT_DIR;
903 return -EEXIST;
904 }
905
906
907
908 ci_sfep = NULL;
909 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
910 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
911
912
913
914
915
916 cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
917 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
918 args->cmpresult = cmp;
919 args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
920 args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
921 if (cmp == XFS_CMP_EXACT)
922 return -EEXIST;
923 ci_sfep = sfep;
924 }
925 }
926 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
927
928
929
930
931 if (!ci_sfep)
932 return -ENOENT;
933
934 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
935 return error;
936}
937
938
939
940
941int
942xfs_dir2_sf_removename(
943 xfs_da_args_t *args)
944{
945 struct xfs_inode *dp = args->dp;
946 struct xfs_mount *mp = dp->i_mount;
947 int byteoff;
948 int entsize;
949 int i;
950 int newsize;
951 int oldsize;
952 xfs_dir2_sf_entry_t *sfep;
953 xfs_dir2_sf_hdr_t *sfp;
954
955 trace_xfs_dir2_sf_removename(args);
956
957 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
958 oldsize = (int)dp->i_d.di_size;
959 ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
960 ASSERT(dp->i_df.if_bytes == oldsize);
961 ASSERT(dp->i_df.if_u1.if_data != NULL);
962 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
963 ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count));
964
965
966
967
968 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
969 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
970 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
971 XFS_CMP_EXACT) {
972 ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
973 args->inumber);
974 break;
975 }
976 }
977
978
979
980 if (i == sfp->count)
981 return -ENOENT;
982
983
984
985 byteoff = (int)((char *)sfep - (char *)sfp);
986 entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
987 newsize = oldsize - entsize;
988
989
990
991 if (byteoff + entsize < oldsize)
992 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
993 oldsize - (byteoff + entsize));
994
995
996
997 sfp->count--;
998 dp->i_d.di_size = newsize;
999
1000
1001
1002 xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
1003 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1004
1005
1006
1007 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1008 if (sfp->i8count == 1)
1009 xfs_dir2_sf_toino4(args);
1010 else
1011 sfp->i8count--;
1012 }
1013 xfs_dir2_sf_check(args);
1014 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1015 return 0;
1016}
1017
1018
1019
1020
1021bool
1022xfs_dir2_sf_replace_needblock(
1023 struct xfs_inode *dp,
1024 xfs_ino_t inum)
1025{
1026 int newsize;
1027 struct xfs_dir2_sf_hdr *sfp;
1028
1029 if (dp->i_df.if_format != XFS_DINODE_FMT_LOCAL)
1030 return false;
1031
1032 sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
1033 newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
1034
1035 return inum > XFS_DIR2_MAX_SHORT_INUM &&
1036 sfp->i8count == 0 && newsize > XFS_IFORK_DSIZE(dp);
1037}
1038
1039
1040
1041
1042int
1043xfs_dir2_sf_replace(
1044 xfs_da_args_t *args)
1045{
1046 struct xfs_inode *dp = args->dp;
1047 struct xfs_mount *mp = dp->i_mount;
1048 int i;
1049 xfs_ino_t ino=0;
1050 int i8elevated;
1051 xfs_dir2_sf_entry_t *sfep;
1052 xfs_dir2_sf_hdr_t *sfp;
1053
1054 trace_xfs_dir2_sf_replace(args);
1055
1056 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
1057 ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
1058 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
1059 ASSERT(dp->i_df.if_u1.if_data != NULL);
1060 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1061 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
1062
1063
1064
1065
1066 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
1067 int error;
1068
1069
1070
1071
1072 if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
1073 error = xfs_dir2_sf_to_block(args);
1074 if (error)
1075 return error;
1076 return xfs_dir2_block_replace(args);
1077 }
1078
1079
1080
1081 xfs_dir2_sf_toino8(args);
1082 i8elevated = 1;
1083 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1084 } else
1085 i8elevated = 0;
1086
1087 ASSERT(args->namelen != 1 || args->name[0] != '.');
1088
1089
1090
1091 if (args->namelen == 2 &&
1092 args->name[0] == '.' && args->name[1] == '.') {
1093 ino = xfs_dir2_sf_get_parent_ino(sfp);
1094 ASSERT(args->inumber != ino);
1095 xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
1096 }
1097
1098
1099
1100 else {
1101 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
1102 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
1103 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
1104 XFS_CMP_EXACT) {
1105 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
1106 ASSERT(args->inumber != ino);
1107 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1108 args->inumber);
1109 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
1110 break;
1111 }
1112 }
1113
1114
1115
1116 if (i == sfp->count) {
1117 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
1118 if (i8elevated)
1119 xfs_dir2_sf_toino4(args);
1120 return -ENOENT;
1121 }
1122 }
1123
1124
1125
1126 if (ino > XFS_DIR2_MAX_SHORT_INUM &&
1127 args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
1128
1129
1130
1131 if (sfp->i8count == 1)
1132 xfs_dir2_sf_toino4(args);
1133 else
1134 sfp->i8count--;
1135 }
1136
1137
1138
1139 if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
1140 args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1141
1142
1143
1144
1145 ASSERT(sfp->i8count != 0);
1146 if (!i8elevated)
1147 sfp->i8count++;
1148 }
1149 xfs_dir2_sf_check(args);
1150 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
1151 return 0;
1152}
1153
1154
1155
1156
1157
1158static void
1159xfs_dir2_sf_toino4(
1160 xfs_da_args_t *args)
1161{
1162 struct xfs_inode *dp = args->dp;
1163 struct xfs_mount *mp = dp->i_mount;
1164 char *buf;
1165 int i;
1166 int newsize;
1167 xfs_dir2_sf_entry_t *oldsfep;
1168 xfs_dir2_sf_hdr_t *oldsfp;
1169 int oldsize;
1170 xfs_dir2_sf_entry_t *sfep;
1171 xfs_dir2_sf_hdr_t *sfp;
1172
1173 trace_xfs_dir2_sf_toino4(args);
1174
1175
1176
1177
1178
1179
1180 oldsize = dp->i_df.if_bytes;
1181 buf = kmem_alloc(oldsize, 0);
1182 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1183 ASSERT(oldsfp->i8count == 1);
1184 memcpy(buf, oldsfp, oldsize);
1185
1186
1187
1188 newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF;
1189 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1190 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1191
1192
1193
1194 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1195 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1196
1197
1198
1199 sfp->count = oldsfp->count;
1200 sfp->i8count = 0;
1201 xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
1202
1203
1204
1205 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1206 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1207 i < sfp->count;
1208 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1209 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
1210 sfep->namelen = oldsfep->namelen;
1211 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
1212 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1213 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1214 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1215 xfs_dir2_sf_put_ftype(mp, sfep,
1216 xfs_dir2_sf_get_ftype(mp, oldsfep));
1217 }
1218
1219
1220
1221 kmem_free(buf);
1222 dp->i_d.di_size = newsize;
1223 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1224}
1225
1226
1227
1228
1229
1230
1231static void
1232xfs_dir2_sf_toino8(
1233 xfs_da_args_t *args)
1234{
1235 struct xfs_inode *dp = args->dp;
1236 struct xfs_mount *mp = dp->i_mount;
1237 char *buf;
1238 int i;
1239 int newsize;
1240 xfs_dir2_sf_entry_t *oldsfep;
1241 xfs_dir2_sf_hdr_t *oldsfp;
1242 int oldsize;
1243 xfs_dir2_sf_entry_t *sfep;
1244 xfs_dir2_sf_hdr_t *sfp;
1245
1246 trace_xfs_dir2_sf_toino8(args);
1247
1248
1249
1250
1251
1252
1253 oldsize = dp->i_df.if_bytes;
1254 buf = kmem_alloc(oldsize, 0);
1255 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1256 ASSERT(oldsfp->i8count == 0);
1257 memcpy(buf, oldsfp, oldsize);
1258
1259
1260
1261 newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF;
1262 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1263 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1264
1265
1266
1267 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1268 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1269
1270
1271
1272 sfp->count = oldsfp->count;
1273 sfp->i8count = 1;
1274 xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
1275
1276
1277
1278 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1279 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1280 i < sfp->count;
1281 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1282 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
1283 sfep->namelen = oldsfep->namelen;
1284 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
1285 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1286 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1287 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1288 xfs_dir2_sf_put_ftype(mp, sfep,
1289 xfs_dir2_sf_get_ftype(mp, oldsfep));
1290 }
1291
1292
1293
1294 kmem_free(buf);
1295 dp->i_d.di_size = newsize;
1296 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1297}
1298