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