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