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

#ifndef _GNU_REISERFS_REISERFS_FS_H
#define	_GNU_REISERFS_REISERFS_FS_H

#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/endian.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/unistd.h>

#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/syslog.h>

#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
//#include <sys/mutex.h>

#include <sys/ctype.h>
#include <sys/bitstring.h>

#include <geom/geom.h>
#include <geom/geom_vfs.h>

#include <gnu/fs/reiserfs/reiserfs_mount.h>
#include <gnu/fs/reiserfs/reiserfs_fs_sb.h>
#include <gnu/fs/reiserfs/reiserfs_fs_i.h>

/* n must be power of 2 */
#define	_ROUND_UP(x, n)	(((x) + (n) - 1u) & ~((n) - 1u))

/* To be ok for alpha and others we have to align structures to 8 byte
 * boundary. */
#define	ROUND_UP(x)	_ROUND_UP(x, 8LL)

/* -------------------------------------------------------------------
 * Global variables
 * -------------------------------------------------------------------*/

extern struct vop_vector reiserfs_vnodeops;
extern struct vop_vector reiserfs_specops;

/* -------------------------------------------------------------------
 * Super block
 * -------------------------------------------------------------------*/

#define	REISERFS_BSIZE 1024

/* ReiserFS leaves the first 64k unused, so that partition labels have
 * enough space. If someone wants to write a fancy bootloader that needs
 * more than 64k, let us know, and this will be increased in size.
 * This number must be larger than than the largest block size on any
 * platform, or code will break. -Hans */
#define	REISERFS_DISK_OFFSET 64
#define	REISERFS_DISK_OFFSET_IN_BYTES                                        \
    ((REISERFS_DISK_OFFSET) * (REISERFS_BSIZE))

/* The spot for the super in versions 3.5 - 3.5.10 (inclusive) */
#define	REISERFS_OLD_DISK_OFFSET 8
#define	REISERFS_OLD_DISK_OFFSET_IN_BYTES                                    \
    ((REISERFS_OLD_DISK_OFFSET) * (REISERFS_BSIZE))

/*
 * Structure of a super block on disk, a version of which in RAM is
 * often accessed as REISERFS_SB(s)->r_rs. The version in RAM is part of
 * a larger structure containing fields never written to disk.
 */

#define	UNSET_HASH	0 /* read_super will guess about, what hash names
			     in directories were sorted with */
#define	TEA_HASH	1
#define	YURA_HASH	2
#define	R5_HASH		3
#define	DEFAULT_HASH	R5_HASH

struct journal_params {
	uint32_t	jp_journal_1st_block;      /* Where does journal start
						      from on its device */
	uint32_t	jp_journal_dev;            /* Journal device st_rdev */
	uint32_t	jp_journal_size;           /* Size of the journal */
	uint32_t	jp_journal_trans_max;      /* Max number of blocks in
						      a transaction */
	uint32_t	jp_journal_magic;          /* Random value made on
						      fs creation (this was
						      sb_journal_block_count) */
	uint32_t	jp_journal_max_batch;      /* Max number of blocks to
						      batch into a
						      transaction */
	uint32_t	jp_journal_max_commit_age; /* In seconds, how old can
						      an async commit be */
	uint32_t	jp_journal_max_trans_age;  /* In seconds, how old a
						      transaction be */
};

struct reiserfs_super_block_v1 {
	uint32_t	s_block_count; /* Blocks count      */
	uint32_t	s_free_blocks; /* Free blocks count */
	uint32_t	s_root_block;  /* Root block number */

	struct journal_params s_journal;

	uint16_t	s_blocksize;
	uint16_t	s_oid_maxsize;
	uint16_t	s_oid_cursize;
	uint16_t	s_umount_state;

	char 		s_magic[10];

	uint16_t	s_fs_state;
	uint32_t	s_hash_function_code;
	uint16_t	s_tree_height;
	uint16_t	s_bmap_nr;
	uint16_t	s_version;
	uint16_t	s_reserved_for_journal;
} __packed;

#define	SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))

struct reiserfs_super_block {
	struct reiserfs_super_block_v1 s_v1;
	uint32_t	s_inode_generation;
	uint32_t	s_flags;
	unsigned char	s_uuid[16];
	unsigned char	s_label[16];
	char		s_unused[88];
} __packed;

#define	SB_SIZE (sizeof(struct reiserfs_super_block))

#define	REISERFS_VERSION_1	0
#define	REISERFS_VERSION_2	2

#define	REISERFS_SB(sbi)		(sbi)
#define	SB_DISK_SUPER_BLOCK(sbi)	(REISERFS_SB(sbi)->s_rs)
#define	SB_V1_DISK_SUPER_BLOCK(sbi)	(&(SB_DISK_SUPER_BLOCK(sbi)->s_v1))

#define	SB_BLOCKSIZE(sbi)						\
    le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_blocksize))
#define	SB_BLOCK_COUNT(sbi)						\
    le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_block_count))
#define	SB_FREE_BLOCKS(s)						\
    le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_free_blocks))

#define	SB_REISERFS_MAGIC(sbi)						\
    (SB_V1_DISK_SUPER_BLOCK(sbi)->s_magic)

#define	SB_ROOT_BLOCK(sbi)						\
    le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_root_block))

#define	SB_TREE_HEIGHT(sbi)						\
    le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_tree_height))

#define	SB_REISERFS_STATE(sbi)						\
    le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_umount_state))

#define	SB_VERSION(sbi)	le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_version))
#define	SB_BMAP_NR(sbi)	le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_bmap_nr))

#define	REISERFS_SUPER_MAGIC_STRING	"ReIsErFs"
#define	REISER2FS_SUPER_MAGIC_STRING	"ReIsEr2Fs"
#define	REISER2FS_JR_SUPER_MAGIC_STRING	"ReIsEr3Fs"

extern const char reiserfs_3_5_magic_string[];
extern const char reiserfs_3_6_magic_string[];
extern const char reiserfs_jr_magic_string[];

int	is_reiserfs_3_5(struct reiserfs_super_block *rs);
int	is_reiserfs_3_6(struct reiserfs_super_block *rs);
int	is_reiserfs_jr(struct reiserfs_super_block *rs);

/* ReiserFS internal error code (used by search_by_key and fix_nodes) */
#define	IO_ERROR	-2

typedef uint32_t b_blocknr_t;
typedef uint32_t unp_t;

struct unfm_nodeinfo {
	unp_t		unfm_nodenum;
	unsigned short	unfm_freespace;
};

/* There are two formats of keys: 3.5 and 3.6 */
#define	KEY_FORMAT_3_5	0
#define	KEY_FORMAT_3_6	1

/* There are two stat datas */
#define	STAT_DATA_V1	0
#define	STAT_DATA_V2	1

#define	REISERFS_I(ip)	(ip)

#define	get_inode_item_key_version(ip)					\
    ((REISERFS_I(ip)->i_flags & i_item_key_version_mask) ?		\
     KEY_FORMAT_3_6 : KEY_FORMAT_3_5)

#define	set_inode_item_key_version(ip, version) ({			\
	if ((version) == KEY_FORMAT_3_6)				\
    		REISERFS_I(ip)->i_flags |= i_item_key_version_mask;	\
    	else								\
    		REISERFS_I(ip)->i_flags &= ~i_item_key_version_mask;	\
})

#define	get_inode_sd_version(ip)					\
    ((REISERFS_I(ip)->i_flags & i_stat_data_version_mask) ?		\
     STAT_DATA_V2 : STAT_DATA_V1)

#define	set_inode_sd_version(inode, version) ({				\
	if((version) == STAT_DATA_V2)					\
		REISERFS_I(ip)->i_flags |= i_stat_data_version_mask;	\
	else								\
		REISERFS_I(ip)->i_flags &= ~i_stat_data_version_mask;	\
})

/* Values for s_umount_state field */
#define	REISERFS_VALID_FS	1
#define	REISERFS_ERROR_FS	2

/* There are 5 item types currently */
#define	TYPE_STAT_DATA		0
#define	TYPE_INDIRECT		1
#define	TYPE_DIRECT		2
#define	TYPE_DIRENTRY		3
#define	TYPE_MAXTYPE		3
#define	TYPE_ANY		15

/* -------------------------------------------------------------------
 * Key & item head
 * -------------------------------------------------------------------*/

struct offset_v1 {
	uint32_t	k_offset;
	uint32_t	k_uniqueness;
} __packed;

struct offset_v2 {
#if BYTE_ORDER == LITTLE_ENDIAN
	/* little endian version */
	uint64_t	k_offset:60;
	uint64_t	k_type:4;
#else
	/* big endian version */
	uint64_t	k_type:4;
	uint64_t	k_offset:60;
#endif
} __packed;

#if (BYTE_ORDER == BIG_ENDIAN)
typedef union {
	struct offset_v2	offset_v2;
	uint64_t		linear;
} __packed offset_v2_esafe_overlay;

static inline uint16_t
offset_v2_k_type(const struct offset_v2 *v2)
{

	offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
	tmp.linear = le64toh(tmp.linear);
	return ((tmp.offset_v2.k_type <= TYPE_MAXTYPE) ?
	    tmp.offset_v2.k_type : TYPE_ANY);
}

static inline void
set_offset_v2_k_type(struct offset_v2 *v2, int type)
{

	offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
	tmp->linear = le64toh(tmp->linear);
	tmp->offset_v2.k_type = type;
	tmp->linear = htole64(tmp->linear);
}

static inline off_t
offset_v2_k_offset(const struct offset_v2 *v2)
{

	offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
	tmp.linear = le64toh(tmp.linear);
	return (tmp.offset_v2.k_offset);
}

static inline void
set_offset_v2_k_offset(struct offset_v2 *v2, off_t offset)
{

	offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
	tmp->linear = le64toh(tmp->linear);
	tmp->offset_v2.k_offset = offset;
	tmp->linear = htole64(tmp->linear);
}
#else /* BYTE_ORDER != BIG_ENDIAN */
#define	offset_v2_k_type(v2)		((v2)->k_type)
#define	set_offset_v2_k_type(v2, val)	(offset_v2_k_type(v2) = (val))
#define	offset_v2_k_offset(v2)		((v2)->k_offset)
#define	set_offset_v2_k_offset(v2, val)	(offset_v2_k_offset(v2) = (val))
#endif /* BYTE_ORDER == BIG_ENDIAN */

/*
 * Key of an item determines its location in the S+tree, and
 * is composed of 4 components
 */
struct key {
	uint32_t	k_dir_id;    /* Packing locality: by default parent
					directory object id */
	uint32_t	k_objectid;  /* Object identifier */
	union {
		struct offset_v1	k_offset_v1;
		struct offset_v2	k_offset_v2;
	} __packed u;
} __packed;

struct cpu_key {
	struct key	on_disk_key;
	int		version;
	int		key_length; /* 3 in all cases but direct2indirect
				       and indirect2direct conversion */
};

/*
 * Our function for comparing keys can compare keys of different
 * lengths. It takes as a parameter the length of the keys it is to
 * compare. These defines are used in determining what is to be passed
 * to it as that parameter.
 */
#define	REISERFS_FULL_KEY_LEN	4
#define	REISERFS_SHORT_KEY_LEN	2

#define	KEY_SIZE	(sizeof(struct key))
#define	SHORT_KEY_SIZE	(sizeof(uint32_t) + sizeof(uint32_t))

/* Return values for search_by_key and clones */
#define	ITEM_FOUND		 1
#define	ITEM_NOT_FOUND		 0
#define	ENTRY_FOUND		 1
#define	ENTRY_NOT_FOUND		 0
#define	DIRECTORY_NOT_FOUND	-1
#define	REGULAR_FILE_FOUND	-2
#define	DIRECTORY_FOUND		-3
#define	BYTE_FOUND		 1
#define	BYTE_NOT_FOUND		 0
#define	FILE_NOT_FOUND		-1

#define	POSITION_FOUND		 1
#define	POSITION_NOT_FOUND	 0

/* Return values for reiserfs_find_entry and search_by_entry_key */
#define	NAME_FOUND		1
#define	NAME_NOT_FOUND		0
#define	GOTO_PREVIOUS_ITEM	2
#define	NAME_FOUND_INVISIBLE	3

/*
 * Everything in the filesystem is stored as a set of items. The item
 * head contains the key of the item, its free space (for indirect
 * items) and specifies the location of the item itself within the
 * block.
 */
struct item_head {
	/*
	 * Everything in the tree is found by searching for it based on
	 * its key.
	 */
	struct key	ih_key;
	union {
		/*
		 * The free space in the last unformatted node of an
		 * indirect item if this is an indirect item. This
		 * equals 0xFFFF iff this is a direct item or stat data
		 * item. Note that the key, not this field, is used to
		 * determine the item type, and thus which field this
		 * union contains.
		 */
		uint16_t	ih_free_space_reserved;

		/*
		 * If this is a directory item, this field equals the number of
		 * directory entries in the directory item.
		 */
		uint16_t	ih_entry_count;
	} __packed u;
	uint16_t	ih_item_len;      /* Total size of the item body */
	uint16_t	ih_item_location; /* An offset to the item body within
					     the block */
	uint16_t	ih_version;       /* 0 for all old items, 2 for new
					     ones. Highest bit is set by fsck
					     temporary, cleaned after all
					     done */
} __packed;

/* Size of item header */
#define	IH_SIZE (sizeof(struct item_head))

#define	ih_free_space(ih)	le16toh((ih)->u.ih_free_space_reserved)
#define	ih_version(ih)		le16toh((ih)->ih_version)
#define	ih_entry_count(ih)	le16toh((ih)->u.ih_entry_count)
#define	ih_location(ih)		le16toh((ih)->ih_item_location)
#define	ih_item_len(ih)		le16toh((ih)->ih_item_len)

/*
 * These operate on indirect items, where you've got an array of ints at
 * a possibly unaligned location. These are a noop on IA32.
 * 
 * p is the array of uint32_t, i is the index into the array, v is the
 * value to store there.
 */
#define	get_unaligned(ptr)						\
    ({ __typeof__(*(ptr)) __tmp;					\
     memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })

#define	put_unaligned(val, ptr)						\
    ({ __typeof__(*(ptr)) __tmp = (val);				\
     memcpy((ptr), &__tmp, sizeof(*(ptr)));				\
     (void)0; })

#define	get_block_num(p, i)	le32toh(get_unaligned((p) + (i)))
#define	put_block_num(p, i, v)	put_unaligned(htole32(v), (p) + (i))

/* In old version uniqueness field shows key type */
#define	V1_SD_UNIQUENESS	0
#define	V1_INDIRECT_UNIQUENESS	0xfffffffe
#define	V1_DIRECT_UNIQUENESS	0xffffffff
#define	V1_DIRENTRY_UNIQUENESS	500
#define	V1_ANY_UNIQUENESS	555

/* Here are conversion routines */
static inline int	uniqueness2type(uint32_t uniqueness);
static inline uint32_t	type2uniqueness(int type);

static inline int
uniqueness2type(uint32_t uniqueness)
{

	switch ((int)uniqueness) {
	case V1_SD_UNIQUENESS:
		return (TYPE_STAT_DATA);
	case V1_INDIRECT_UNIQUENESS:
		return (TYPE_INDIRECT);
	case V1_DIRECT_UNIQUENESS:
		return (TYPE_DIRECT);
	case V1_DIRENTRY_UNIQUENESS:
		return (TYPE_DIRENTRY);
	default:
		log(LOG_NOTICE, "reiserfs: unknown uniqueness (%u)\n",
		    uniqueness);
	case V1_ANY_UNIQUENESS:
		return (TYPE_ANY);
	}
}

static inline uint32_t
type2uniqueness(int type)
{

	switch (type) {
	case TYPE_STAT_DATA:
		return (V1_SD_UNIQUENESS);
	case TYPE_INDIRECT:
		return (V1_INDIRECT_UNIQUENESS);
	case TYPE_DIRECT:
		return (V1_DIRECT_UNIQUENESS);
	case TYPE_DIRENTRY:
		return (V1_DIRENTRY_UNIQUENESS);
	default:
		log(LOG_NOTICE, "reiserfs: unknown type (%u)\n", type);
	case TYPE_ANY:
		return (V1_ANY_UNIQUENESS);
	}
}

/*
 * Key is pointer to on disk key which is stored in le, result is cpu,
 * there is no way to get version of object from key, so, provide
 * version to these defines.
 */
static inline off_t
le_key_k_offset(int version, const struct key *key)
{

	return ((version == KEY_FORMAT_3_5) ?
	    le32toh(key->u.k_offset_v1.k_offset) :
	    offset_v2_k_offset(&(key->u.k_offset_v2)));
}

static inline off_t
le_ih_k_offset(const struct item_head *ih)
{

	return (le_key_k_offset(ih_version(ih), &(ih->ih_key)));
}

static inline off_t
le_key_k_type(int version, const struct key *key)
{

	return ((version == KEY_FORMAT_3_5) ?
	    uniqueness2type(le32toh(key->u.k_offset_v1.k_uniqueness)) :
	    offset_v2_k_type(&(key->u.k_offset_v2)));
}

static inline off_t
le_ih_k_type(const struct item_head *ih)
{
	return (le_key_k_type(ih_version(ih), &(ih->ih_key)));
}

static inline void
set_le_key_k_offset(int version, struct key *key, off_t offset)
{

	(version == KEY_FORMAT_3_5) ?
	    (key->u.k_offset_v1.k_offset = htole32(offset)) :
	    (set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
}

static inline void
set_le_ih_k_offset(struct item_head *ih, off_t offset)
{

	set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
}

static inline void
set_le_key_k_type(int version, struct key *key, int type)
{

	(version == KEY_FORMAT_3_5) ?
	    (key->u.k_offset_v1.k_uniqueness =
	     htole32(type2uniqueness(type))) :
	    (set_offset_v2_k_type(&(key->u.k_offset_v2), type));
}

static inline void
set_le_ih_k_type(struct item_head *ih, int type)
{

	set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
}

#define	is_direntry_le_key(version, key)				\
    (le_key_k_type(version, key) == TYPE_DIRENTRY)
#define	is_direct_le_key(version, key)					\
    (le_key_k_type(version, key) == TYPE_DIRECT)
#define	is_indirect_le_key(version, key)				\
    (le_key_k_type(version, key) == TYPE_INDIRECT)
#define	is_statdata_le_key(version, key)				\
    (le_key_k_type(version, key) == TYPE_STAT_DATA)

/* Item header has version. */
#define	is_direntry_le_ih(ih)						\
    is_direntry_le_key(ih_version(ih), &((ih)->ih_key))
#define	is_direct_le_ih(ih)						\
    is_direct_le_key(ih_version(ih), &((ih)->ih_key))
#define	is_indirect_le_ih(ih)						\
    is_indirect_le_key(ih_version(ih), &((ih)->ih_key))
#define	is_statdata_le_ih(ih)						\
    is_statdata_le_key(ih_version(ih), &((ih)->ih_key))

static inline void
set_cpu_key_k_offset(struct cpu_key *key, off_t offset)
{

	(key->version == KEY_FORMAT_3_5) ?
	    (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
	    (key->on_disk_key.u.k_offset_v2.k_offset = offset);
}

static inline void
set_cpu_key_k_type(struct cpu_key *key, int type)
{

	(key->version == KEY_FORMAT_3_5) ?
	    (key->on_disk_key.u.k_offset_v1.k_uniqueness =
	     type2uniqueness(type)):
	    (key->on_disk_key.u.k_offset_v2.k_type = type);
}

#define	is_direntry_cpu_key(key)	(cpu_key_k_type (key) == TYPE_DIRENTRY)
#define	is_direct_cpu_key(key)		(cpu_key_k_type (key) == TYPE_DIRECT)
#define	is_indirect_cpu_key(key)	(cpu_key_k_type (key) == TYPE_INDIRECT)
#define	is_statdata_cpu_key(key)	(cpu_key_k_type (key) == TYPE_STAT_DATA)

/* Maximal length of item */
#define	MAX_ITEM_LEN(block_size)	(block_size - BLKH_SIZE - IH_SIZE)
#define	MIN_ITEM_LEN			1

/* Object identifier for root dir */
#define	REISERFS_ROOT_OBJECTID		2
#define	REISERFS_ROOT_PARENT_OBJECTID	1

/* key is pointer to cpu key, result is cpu */
static inline off_t
cpu_key_k_offset(const struct cpu_key *key)
{

	return ((key->version == KEY_FORMAT_3_5) ?
	    key->on_disk_key.u.k_offset_v1.k_offset :
	    key->on_disk_key.u.k_offset_v2.k_offset);
}

static inline off_t
cpu_key_k_type(const struct cpu_key *key)
{

	return ((key->version == KEY_FORMAT_3_5) ?
	    uniqueness2type(key->on_disk_key.u.k_offset_v1.k_uniqueness) :
	    key->on_disk_key.u.k_offset_v2.k_type);
}

/*
 * Header of a disk block.  More precisely, header of a formatted leaf
 * or internal node, and not the header of an unformatted node.
 */
struct block_head {
	uint16_t	blk_level;            /* Level of a block in the
						 tree. */
	uint16_t	blk_nr_item;          /* Number of keys/items in a
						 block. */
	uint16_t	blk_free_space;       /* Block free space in bytes. */
	uint16_t	blk_reserved;         /* Dump this in v4/planA */
	struct key	blk_right_delim_key;  /* Kept only for compatibility */
};

#define	BLKH_SIZE		(sizeof(struct block_head))
#define	blkh_level(p_blkh)	(le16toh((p_blkh)->blk_level))
#define	blkh_nr_item(p_blkh)	(le16toh((p_blkh)->blk_nr_item))
#define	blkh_free_space(p_blkh)	(le16toh((p_blkh)->blk_free_space))

#define	FREE_LEVEL	0 /* When node gets removed from the tree its
			     blk_level is set to FREE_LEVEL. It is then
			     used to see whether the node is still in the
			     tree */

/* Values for blk_level field of the struct block_head */
#define	DISK_LEAF_NODE_LEVEL	1 /* Leaf node level.*/

/*
 * Given the buffer head of a formatted node, resolve to the block head
 * of that node.
 */
#define	B_BLK_HEAD(p_s_bp)	((struct block_head *)((p_s_bp)->b_data))
#define	B_NR_ITEMS(p_s_bp)	(blkh_nr_item(B_BLK_HEAD(p_s_bp)))
#define	B_LEVEL(p_s_bp)		(blkh_level(B_BLK_HEAD(p_s_bp)))
#define	B_FREE_SPACE(p_s_bp)	(blkh_free_space(B_BLK_HEAD(p_s_bp)))

/* -------------------------------------------------------------------
 * Stat data
 * -------------------------------------------------------------------*/

/*
 * Old stat data is 32 bytes long. We are going to distinguish new one
 * by different size.
 */
struct stat_data_v1 {
	uint16_t	sd_mode;  /* File type, permissions */
	uint16_t	sd_nlink; /* Number of hard links */
	uint16_t	sd_uid;   /* Owner */
	uint16_t	sd_gid;   /* Group */
	uint32_t	sd_size;  /* File size */
	uint32_t	sd_atime; /* Time of last access */
	uint32_t	sd_mtime; /* Time file was last modified  */
	uint32_t	sd_ctime; /* Time inode (stat data) was last changed
				     (except changes to sd_atime and
				     sd_mtime) */
	union {
		uint32_t 	sd_rdev;
		uint32_t	sd_blocks;  /* Number of blocks file uses */
	} __packed u;
	uint32_t	sd_first_direct_byte; /* First byte of file which is
						 stored in a direct item:
						 except that if it equals 1
						 it is a symlink and if it
						 equals ~(uint32_t)0 there
						 is no direct item. The
						 existence of this field
						 really grates on me. Let's
						 replace it with a macro based
						 on sd_size and our tail
						 suppression policy. Someday.
						 -Hans */
} __packed;

#define	SD_V1_SIZE			(sizeof(struct stat_data_v1))
#define	stat_data_v1(ih)		(ih_version (ih) == KEY_FORMAT_3_5)
#define	sd_v1_mode(sdp)			(le16toh((sdp)->sd_mode))
#define	set_sd_v1_mode(sdp, v)		((sdp)->sd_mode = htole16(v))
#define	sd_v1_nlink(sdp)		(le16toh((sdp)->sd_nlink))
#define	set_sd_v1_nlink(sdp, v)		((sdp)->sd_nlink = htole16(v))
#define	sd_v1_uid(sdp)			(le16toh((sdp)->sd_uid))
#define	set_sd_v1_uid(sdp, v)		((sdp)->sd_uid = htole16(v))
#define	sd_v1_gid(sdp)			(le16toh((sdp)->sd_gid))
#define	set_sd_v1_gid(sdp, v)		((sdp)->sd_gid = htole16(v))
#define	sd_v1_size(sdp)			(le32toh((sdp)->sd_size))
#define	set_sd_v1_size(sdp, v)		((sdp)->sd_size = htole32(v))
#define	sd_v1_atime(sdp)		(le32toh((sdp)->sd_atime))
#define	set_sd_v1_atime(sdp, v)		((sdp)->sd_atime = htole32(v))
#define	sd_v1_mtime(sdp)		(le32toh((sdp)->sd_mtime))
#define	set_sd_v1_mtime(sdp, v)		((sdp)->sd_mtime = htole32(v))
#define	sd_v1_ctime(sdp)		(le32toh((sdp)->sd_ctime))
#define	set_sd_v1_ctime(sdp, v)		((sdp)->sd_ctime = htole32(v))
#define	sd_v1_rdev(sdp)			(le32toh((sdp)->u.sd_rdev))
#define	set_sd_v1_rdev(sdp, v)		((sdp)->u.sd_rdev = htole32(v))
#define	sd_v1_blocks(sdp)		(le32toh((sdp)->u.sd_blocks))
#define	set_sd_v1_blocks(sdp, v)	((sdp)->u.sd_blocks = htole32(v))
#define	sd_v1_first_direct_byte(sdp)					\
    (le32toh((sdp)->sd_first_direct_byte))
#define	set_sd_v1_first_direct_byte(sdp, v)				\
    ((sdp)->sd_first_direct_byte = htole32(v))

/*
 * We want common flags to have the same values as in ext2,
 * so chattr(1) will work without problems
 */
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_dinode.h>
#define	REISERFS_IMMUTABLE_FL	EXT2_IMMUTABLE
#define	REISERFS_APPEND_FL	EXT2_APPEND
#define	REISERFS_SYNC_FL	EXT2_SYNC
#define	REISERFS_NOATIME_FL	EXT2_NOATIME
#define	REISERFS_NODUMP_FL	EXT2_NODUMP
#define	REISERFS_SECRM_FL	EXT2_SECRM
#define	REISERFS_UNRM_FL	EXT2_UNRM
#define	REISERFS_COMPR_FL	EXT2_COMPR
#define	REISERFS_NOTAIL_FL	EXT2_NOTAIL_FL

/*
 * Stat Data on disk (reiserfs version of UFS disk inode minus the
 * address blocks)
 */
struct stat_data {
	uint16_t	sd_mode;  /* File type, permissions */
	uint16_t	sd_attrs; /* Persistent inode flags */
	uint32_t	sd_nlink; /* Number of hard links */
	uint64_t	sd_size;  /* File size */
	uint32_t	sd_uid;   /* Owner */
	uint32_t	sd_gid;   /* Group */
	uint32_t	sd_atime; /* Time of last access */
	uint32_t	sd_mtime; /* Time file was last modified  */
	uint32_t	sd_ctime; /* Time inode (stat data) was last changed
				     (except changes to sd_atime and
				     sd_mtime) */
	uint32_t	sd_blocks;
	union {
		uint32_t	sd_rdev;
		uint32_t	sd_generation;
		//uint32_t	sd_first_direct_byte; 
		/*
		 * First byte of file which is stored in a
		 * direct item: except that if it equals 1
		 * it is a symlink and if it equals
		 * ~(uint32_t)0 there is no direct item.  The
		 * existence of this field really grates
		 * on me. Let's replace it with a macro
		 * based on sd_size and our tail
		 * suppression policy?
		 */
	} __packed u;
} __packed;

/* This is 44 bytes long */
#define	SD_SIZE				(sizeof(struct stat_data))
#define	SD_V2_SIZE			SD_SIZE
#define	stat_data_v2(ih)		(ih_version (ih) == KEY_FORMAT_3_6)
#define	sd_v2_mode(sdp)			(le16toh((sdp)->sd_mode))
#define	set_sd_v2_mode(sdp, v)		((sdp)->sd_mode = htole16(v))
/* sd_reserved */
/* set_sd_reserved */
#define	sd_v2_nlink(sdp)		(le32toh((sdp)->sd_nlink))
#define	set_sd_v2_nlink(sdp, v)		((sdp)->sd_nlink = htole32(v))
#define	sd_v2_size(sdp)			(le64toh((sdp)->sd_size))
#define	set_sd_v2_size(sdp, v)		((sdp)->sd_size = cpu_to_le64(v))
#define	sd_v2_uid(sdp)			(le32toh((sdp)->sd_uid))
#define	set_sd_v2_uid(sdp, v)		((sdp)->sd_uid = htole32(v))
#define	sd_v2_gid(sdp)			(le32toh((sdp)->sd_gid))
#define	set_sd_v2_gid(sdp, v)		((sdp)->sd_gid = htole32(v))
#define	sd_v2_atime(sdp)		(le32toh((sdp)->sd_atime))
#define	set_sd_v2_atime(sdp, v)		((sdp)->sd_atime = htole32(v))
#define	sd_v2_mtime(sdp)		(le32toh((sdp)->sd_mtime))
#define	set_sd_v2_mtime(sdp, v)		((sdp)->sd_mtime = htole32(v))
#define	sd_v2_ctime(sdp)		(le32toh((sdp)->sd_ctime))
#define	set_sd_v2_ctime(sdp, v)		((sdp)->sd_ctime = htole32(v))
#define	sd_v2_blocks(sdp)		(le32toh((sdp)->sd_blocks))
#define	set_sd_v2_blocks(sdp, v)	((sdp)->sd_blocks = htole32(v))
#define	sd_v2_rdev(sdp)			(le32toh((sdp)->u.sd_rdev))
#define	set_sd_v2_rdev(sdp, v)		((sdp)->u.sd_rdev = htole32(v))
#define	sd_v2_generation(sdp)		(le32toh((sdp)->u.sd_generation))
#define	set_sd_v2_generation(sdp, v)	((sdp)->u.sd_generation = htole32(v))
#define	sd_v2_attrs(sdp)		(le16toh((sdp)->sd_attrs))
#define	set_sd_v2_attrs(sdp, v)		((sdp)->sd_attrs = htole16(v))

/* -------------------------------------------------------------------
 * Directory structure
 * -------------------------------------------------------------------*/

#define	SD_OFFSET		0
#define	SD_UNIQUENESS		0
#define	DOT_OFFSET		1
#define	DOT_DOT_OFFSET		2
#define	DIRENTRY_UNIQUENESS	500

#define	FIRST_ITEM_OFFSET	1

struct reiserfs_de_head {
	uint32_t	deh_offset;    /* Third component of the directory
					  entry key */
	uint32_t	deh_dir_id;    /* Objectid of the parent directory of
					  the object, that is referenced by
					  directory entry */
	uint32_t	deh_objectid;  /* Objectid of the object, that is
					  referenced by directory entry */
	uint16_t	deh_location;  /* Offset of name in the whole item */
	uint16_t	deh_state;     /* Whether 1) entry contains stat data
					  (for future), and 2) whether entry
					  is hidden (unlinked) */
} __packed;

#define	DEH_SIZE			sizeof(struct reiserfs_de_head)
#define	deh_offset(p_deh)		(le32toh((p_deh)->deh_offset))
#define	deh_dir_id(p_deh)		(le32toh((p_deh)->deh_dir_id))
#define	deh_objectid(p_deh)		(le32toh((p_deh)->deh_objectid))
#define	deh_location(p_deh)		(le16toh((p_deh)->deh_location))
#define	deh_state(p_deh)		(le16toh((p_deh)->deh_state))

#define	put_deh_offset(p_deh, v)	((p_deh)->deh_offset = htole32((v)))
#define	put_deh_dir_id(p_deh, v)	((p_deh)->deh_dir_id = htole32((v)))
#define	put_deh_objectid(p_deh, v)	((p_deh)->deh_objectid = htole32((v)))
#define	put_deh_location(p_deh, v)	((p_deh)->deh_location = htole16((v)))
#define	put_deh_state(p_deh, v)		((p_deh)->deh_state = htole16((v)))

/* Empty directory contains two entries "." and ".." and their headers */
#define	EMPTY_DIR_SIZE							\
    (DEH_SIZE * 2 + ROUND_UP(strlen(".")) + ROUND_UP(strlen("..")))

/* Old format directories have this size when empty */
#define	EMPTY_DIR_SIZE_V1	(DEH_SIZE * 2 + 3)

#define	DEH_Statdata	0 /* Not used now */
#define	DEH_Visible	2

/* Macro to map Linux' *_bit function to bitstring.h macros */
#define	set_bit(bit, name)		bit_set((bitstr_t *)name, bit)
#define	clear_bit(bit, name)		bit_clear((bitstr_t *)name, bit)
#define	test_bit(bit, name)		bit_test((bitstr_t *)name, bit)

#define	set_bit_unaligned(bit, name)	set_bit(bit, name)
#define	clear_bit_unaligned(bit, name)	clear_bit(bit, name)
#define	test_bit_unaligned(bit, name)	test_bit(bit, name)

#define	mark_de_with_sd(deh)						\
    set_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
#define	mark_de_without_sd(deh)						\
    clear_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
#define	mark_de_visible(deh)						\
    set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
#define	mark_de_hidden(deh)						\
    clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))

#define	de_with_sd(deh)							\
    test_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
#define	de_visible(deh)							\
    test_bit_unaligned(DEH_Visible, &((deh)->deh_state))
#define	de_hidden(deh)							\
    !test_bit_unaligned(DEH_Visible, &((deh)->deh_state))

/* Two entries per block (at least) */
#define	REISERFS_MAX_NAME(block_size)	255

/*
 * This structure is used for operations on directory entries. It is not
 * a disk structure. When reiserfs_find_entry or search_by_entry_key
 * find directory entry, they return filled reiserfs_dir_entry structure
 */
struct reiserfs_dir_entry {
	struct buf *de_bp;
	int	 de_item_num;
	struct item_head *de_ih;
	int	 de_entry_num;
	struct reiserfs_de_head *de_deh;
	int	 de_entrylen;
	int	 de_namelen;
	char	*de_name;
	char	*de_gen_number_bit_string;

	uint32_t de_dir_id;
	uint32_t de_objectid;

	struct cpu_key de_entry_key;
};

/* Pointer to file name, stored in entry */
#define	B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh)				\
    (B_I_PITEM(bp, ih) + deh_location(deh))

/* Length of name */
#define	I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih, deh, entry_num)		\
    (I_DEH_N_ENTRY_LENGTH(ih, deh, entry_num) -				\
     (de_with_sd(deh) ? SD_SIZE : 0))

/* Hash value occupies bits from 7 up to 30 */
#define	GET_HASH_VALUE(offset)		((offset) & 0x7fffff80LL)

/* Generation number occupies 7 bits starting from 0 up to 6 */
#define	GET_GENERATION_NUMBER(offset)	((offset) & 0x7fLL)
#define	MAX_GENERATION_NUMBER		127

/* Get item body */
#define	B_I_PITEM(bp, ih)	((bp)->b_data + ih_location(ih))
#define	B_I_DEH(bp, ih)		((struct reiserfs_de_head *)(B_I_PITEM(bp, ih)))

/*
 * Length of the directory entry in directory item. This define
 * calculates length of i-th directory entry using directory entry
 * locations from dir entry head. When it calculates length of 0-th
 * directory entry, it uses length of whole item in place of entry
 * location of the non-existent following entry in the calculation. See
 * picture above.
 */
static inline int
entry_length (const struct buf *bp, const struct item_head *ih,
    int pos_in_item)
{
	struct reiserfs_de_head *deh;

	deh = B_I_DEH(bp, ih) + pos_in_item;
	if (pos_in_item)
		return (deh_location(deh - 1) - deh_location(deh));

	return (ih_item_len(ih) - deh_location(deh));
}

/*
 * Number of entries in the directory item, depends on ENTRY_COUNT
 * being at the start of directory dynamic data.
 */
#define	I_ENTRY_COUNT(ih)	(ih_entry_count((ih)))

/* -------------------------------------------------------------------
 * Disk child
 * -------------------------------------------------------------------*/

/*
 * Disk child pointer: The pointer from an internal node of the tree
 * to a node that is on disk.
 */
struct disk_child {
	uint32_t	dc_block_number; /* Disk child's block number. */
	uint16_t	dc_size;         /* Disk child's used space. */
	uint16_t	dc_reserved;
};

#define	DC_SIZE			(sizeof(struct disk_child))
#define	dc_block_number(dc_p)	(le32toh((dc_p)->dc_block_number))
#define	dc_size(dc_p)		(le16toh((dc_p)->dc_size))
#define	put_dc_block_number(dc_p, val)					\
    do { (dc_p)->dc_block_number = htole32(val); } while (0)
#define	put_dc_size(dc_p, val)						\
    do { (dc_p)->dc_size = htole16(val); } while (0)

/* Get disk child by buffer header and position in the tree node. */
#define	B_N_CHILD(p_s_bp, n_pos)					\
    ((struct disk_child *)((p_s_bp)->b_data + BLKH_SIZE +		\
			   B_NR_ITEMS(p_s_bp) * KEY_SIZE +		\
			   DC_SIZE * (n_pos)))

/* Get disk child number by buffer header and position in the tree node. */
#define	B_N_CHILD_NUM(p_s_bp, n_pos)					\
    (dc_block_number(B_N_CHILD(p_s_bp, n_pos)))
#define	PUT_B_N_CHILD_NUM(p_s_bp, n_pos, val)				\
    (put_dc_block_number(B_N_CHILD(p_s_bp, n_pos), val))

/* -------------------------------------------------------------------
 * Path structures and defines
 * -------------------------------------------------------------------*/

struct path_element {
	struct buf	*pe_buffer;  /* Pointer to the buffer at the path in
					the tree. */
	int		pe_position; /* Position in the tree node which is
					placed in the buffer above. */
};

#define	MAX_HEIGHT			5 /* Maximal height of a tree. Don't
					     change this without changing
					     JOURNAL_PER_BALANCE_CNT */
#define	EXTENDED_MAX_HEIGHT		7 /* Must be equals MAX_HEIGHT +
					     FIRST_PATH_ELEMENT_OFFSET */
#define	FIRST_PATH_ELEMENT_OFFSET	2 /* Must be equal to at least 2. */
#define	ILLEGAL_PATH_ELEMENT_OFFSET	1 /* Must be equal to
					     FIRST_PATH_ELEMENT_OFFSET - 1 */
#define	MAX_FEB_SIZE			6 /* This MUST be MAX_HEIGHT + 1.
					     See about FEB below */

struct path {
	/* Length of the array below. */
	int	path_length;
	/* Array of the path element */
	struct path_element path_elements[EXTENDED_MAX_HEIGHT];
	int	pos_in_item;
};

#define	pos_in_item(path)	((path)->pos_in_item)

#ifdef __amd64__
/* To workaround a bug in gcc. He generates a call to memset() which
 * is a inline function; this causes a compile time error. */
#define	INITIALIZE_PATH(var)						\
    struct path var;							\
    bzero(&var, sizeof(var));						\
    var.path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
#else
#define	INITIALIZE_PATH(var)						\
    struct path var = { ILLEGAL_PATH_ELEMENT_OFFSET, }
#endif

/* Get path element by path and path position. */
#define	PATH_OFFSET_PELEMENT(p_s_path, n_offset)			\
    ((p_s_path)->path_elements + (n_offset))

/* Get buffer header at the path by path and path position. */
#define	PATH_OFFSET_PBUFFER(p_s_path, n_offset)				\
    (PATH_OFFSET_PELEMENT(p_s_path, n_offset)->pe_buffer)

/* Get position in the element at the path by path and path position. */
#define	PATH_OFFSET_POSITION(p_s_path, n_offset)			\
    (PATH_OFFSET_PELEMENT(p_s_path, n_offset)->pe_position)

#define	PATH_PLAST_BUFFER(p_s_path)					\
    (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))

#define	PATH_LAST_POSITION(p_s_path)					\
    (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))

#define	PATH_PITEM_HEAD(p_s_path)					\
    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path), PATH_LAST_POSITION(p_s_path))

#define	get_last_bp(path)	PATH_PLAST_BUFFER(path)
#define	get_ih(path)		PATH_PITEM_HEAD(path)

/* -------------------------------------------------------------------
 * Misc.
 * -------------------------------------------------------------------*/

/* Size of pointer to the unformatted node. */
#define	UNFM_P_SIZE	(sizeof(unp_t))
#define	UNFM_P_SHIFT	2

/* In in-core inode key is stored on le form */
#define	INODE_PKEY(ip)	((struct key *)(REISERFS_I(ip)->i_key))

#define	MAX_UL_INT	0xffffffff
#define	MAX_INT		0x7ffffff
#define	MAX_US_INT	0xffff

/* The purpose is to detect overflow of an unsigned short */
#define	REISERFS_LINK_MAX	(MAX_US_INT - 1000)

#define	fs_generation(sbi)	(REISERFS_SB(sbi)->s_generation_counter)
#define	get_generation(sbi)	(fs_generation(sbi))

#define	__fs_changed(gen, sbi)	(gen != get_generation (sbi))
/*#define	fs_changed(gen, sbi)	({ cond_resched();		\
    __fs_changed(gen, sbi); })*/
#define	fs_changed(gen, sbi)	(__fs_changed(gen, sbi))

/* -------------------------------------------------------------------
 * Fixate node
 * -------------------------------------------------------------------*/

/*
 * To make any changes in the tree we always first find node, that
 * contains item to be changed/deleted or place to insert a new item.
 * We call this node S. To do balancing we need to decide what we will
 * shift to left/right neighbor, or to a new node, where new item will
 * be etc. To make this analysis simpler we build virtual node. Virtual
 * node is an array of items, that will replace items of node S. (For
 * instance if we are going to delete an item, virtual node does not
 * contain it). Virtual node keeps information about item sizes and
 * types, mergeability of first and last items, sizes of all entries in
 * directory item. We use this array of items when calculating what we
 * can shift to neighbors and how many nodes we have to have if we do
 * not any shiftings, if we shift to left/right neighbor or to both.
 */
struct virtual_item {
	int			 vi_index;    /* Index in the array of item
						 operations */
	unsigned short		 vi_type;     /* Left/right mergeability */
	unsigned short		 vi_item_len; /* Length of item that it will
						 have after balancing */
	struct item_head	*vi_ih;
	const char		*vi_item;     /* Body of item (old or new) */
	const void		*vi_new_data; /* 0 always but paste mode */
	void			*vi_uarea;    /* Item specific area */
};

struct virtual_node {
	char		*vn_free_ptr; /* This is a pointer to the free space
					 in the buffer */
	unsigned short	 vn_nr_item;  /* Number of items in virtual node */
	short		 vn_size;     /* Size of node , that node would have
					 if it has unlimited size and no
					 balancing is performed */
	short		 vn_mode;     /* Mode of balancing (paste, insert,
					 delete, cut) */
	short		 vn_affected_item_num;
	short		 vn_pos_in_item;
	struct item_head *vn_ins_ih;  /* Item header of inserted item, 0 for
					 other modes */
	const void	*vn_data;
	struct virtual_item *vn_vi;   /* Array of items (including a new one,
					 excluding item to be deleted) */
};

/* Used by directory items when creating virtual nodes */
struct direntry_uarea {
	int		flags;
	uint16_t	entry_count;
	uint16_t	entry_sizes[1];
} __packed;

/* -------------------------------------------------------------------
 * Tree balance
 * -------------------------------------------------------------------*/

struct reiserfs_iget_args {
	uint32_t	objectid;
	uint32_t	dirid;
};

struct item_operations {
	int	(*bytes_number)(struct item_head * ih, int block_size);
	void	(*decrement_key)(struct cpu_key *);
	int	(*is_left_mergeable)(struct key * ih, unsigned long bsize);
	void	(*print_item)(struct item_head *, char * item);
	void	(*check_item)(struct item_head *, char * item);

	int	(*create_vi)(struct virtual_node * vn,
	    struct virtual_item * vi, int is_affected, int insert_size);
	int	(*check_left)(struct virtual_item * vi, int free,
	    int start_skip, int end_skip);
	int	(*check_right)(struct virtual_item * vi, int free);
	int	(*part_size)(struct virtual_item * vi, int from, int to);
	int	(*unit_num)(struct virtual_item * vi);
	void	(*print_vi)(struct virtual_item * vi);
};

extern struct item_operations *item_ops[TYPE_ANY + 1];

#define	op_bytes_number(ih, bsize)					\
    item_ops[le_ih_k_type(ih)]->bytes_number(ih, bsize)

#define	COMP_KEYS	comp_keys
#define	COMP_SHORT_KEYS	comp_short_keys

/* Get the item header */
#define	B_N_PITEM_HEAD(bp, item_num)					\
    ((struct item_head *)((bp)->b_data + BLKH_SIZE) + (item_num))

/* Get key */
#define	B_N_PDELIM_KEY(bp, item_num)					\
    ((struct key *)((bp)->b_data + BLKH_SIZE) + (item_num))

/* -------------------------------------------------------------------
 * Function declarations
 * -------------------------------------------------------------------*/

/* reiserfs_stree.c */
int	B_IS_IN_TREE(const struct buf *p_s_bp);

extern void	copy_item_head(struct item_head * p_v_to,
		    const struct item_head * p_v_from);

extern int	comp_keys(const struct key *le_key,
		    const struct cpu_key *cpu_key);
extern int	comp_short_keys(const struct key *le_key,
		    const struct cpu_key *cpu_key);

extern int	comp_le_keys(const struct key *, const struct key *);

static inline int
le_key_version(const struct key *key)
{
	int type;

	type = offset_v2_k_type(&(key->u.k_offset_v2));
	if (type != TYPE_DIRECT && type != TYPE_INDIRECT &&
	    type != TYPE_DIRENTRY)
		return (KEY_FORMAT_3_5);

	return (KEY_FORMAT_3_6);
}

static inline void
copy_key(struct key *to, const struct key *from)
{

	memcpy(to, from, KEY_SIZE);
}

const struct key	*get_lkey(const struct path *p_s_chk_path,
			    const struct reiserfs_sb_info *p_s_sbi);
const struct key	*get_rkey(const struct path *p_s_chk_path,
			    const struct reiserfs_sb_info *p_s_sbi);
int	bin_search(const void * p_v_key, const void * p_v_base,
		    int p_n_num, int p_n_width, int * p_n_pos);

void	pathrelse(struct path *p_s_search_path);
int	reiserfs_check_path(struct path *p);

int	search_by_key(struct reiserfs_sb_info *p_s_sbi,
	    const struct cpu_key *p_s_key,
	    struct path *p_s_search_path,
	    int n_stop_level);
#define	search_item(sbi, key, path)					\
    search_by_key(sbi, key, path, DISK_LEAF_NODE_LEVEL)
int	search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi,
	    const struct cpu_key *p_s_cpu_key,
	    struct path *p_s_search_path);
void	decrement_counters_in_path(struct path *p_s_search_path);

/* reiserfs_inode.c */
vop_read_t	reiserfs_read;
vop_inactive_t	reiserfs_inactive;
vop_reclaim_t	reiserfs_reclaim;

int	reiserfs_get_block(struct reiserfs_node *ip, long block,
	    off_t offset, struct uio *uio);

void	make_cpu_key(struct cpu_key *cpu_key, struct reiserfs_node *ip,
	    off_t offset, int type, int key_length);

void	reiserfs_read_locked_inode(struct reiserfs_node *ip,
	    struct reiserfs_iget_args *args);
int	reiserfs_iget(struct mount *mp, const struct cpu_key *key,
	    struct vnode **vpp, struct thread *td);

void	sd_attrs_to_i_attrs(uint16_t sd_attrs, struct reiserfs_node *ip);
void	i_attrs_to_sd_attrs(struct reiserfs_node *ip, uint16_t *sd_attrs);

/* reiserfs_namei.c */
vop_readdir_t		reiserfs_readdir;
vop_cachedlookup_t	reiserfs_lookup;

void	set_de_name_and_namelen(struct reiserfs_dir_entry * de);
int	search_by_entry_key(struct reiserfs_sb_info *sbi,
	    const struct cpu_key *key, struct path *path,
	    struct reiserfs_dir_entry *de);

/* reiserfs_prints.c */
char	*reiserfs_hashname(int code);
void	 reiserfs_dump_buffer(caddr_t buf, off_t len);

#if defined(REISERFS_DEBUG)
#define	reiserfs_log(lvl, fmt, ...)					\
    log(lvl, "ReiserFS/%s: " fmt, __func__, ## __VA_ARGS__)
#elif defined (REISERFS_DEBUG_CONS)
#define	reiserfs_log(lvl, fmt, ...)					\
    printf("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__)
#else
#define	reiserfs_log(lvl, fmt, ...)
#endif

#define	reiserfs_log_0(lvl, fmt, ...)					\
    printf("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__)

/* reiserfs_hashes.c */
uint32_t	keyed_hash(const signed char *msg, int len);
uint32_t	yura_hash(const signed char *msg, int len);
uint32_t	r5_hash(const signed char *msg, int len);

#define	reiserfs_test_le_bit  test_bit

#endif /* !defined _GNU_REISERFS_REISERFS_FS_H */
OpenPOWER on IntegriCloud