item_ops.c 18.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5
/*
 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
 */

#include <linux/time.h>
6
#include "reiserfs.h"
Linus Torvalds's avatar
Linus Torvalds committed
7

8 9 10 11
/*
 * this contains item handlers for old item types: sd, direct,
 * indirect, directory
 */
Linus Torvalds's avatar
Linus Torvalds committed
12

13 14 15 16
/*
 * and where are the comments? how about saying where we can find an
 * explanation of each item handler method? -Hans
 */
Linus Torvalds's avatar
Linus Torvalds committed
17

18
/* stat data functions */
19
static int sd_bytes_number(struct item_head *ih, int block_size)
Linus Torvalds's avatar
Linus Torvalds committed
20
{
21
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
22 23
}

24
static void sd_decrement_key(struct cpu_key *key)
Linus Torvalds's avatar
Linus Torvalds committed
25
{
26 27
	key->on_disk_key.k_objectid--;
	set_cpu_key_k_type(key, TYPE_ANY);
28
	set_cpu_key_k_offset(key, (loff_t)(~0ULL >> 1));
Linus Torvalds's avatar
Linus Torvalds committed
29 30
}

31
static int sd_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize)
Linus Torvalds's avatar
Linus Torvalds committed
32
{
33
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
34 35
}

36
static void sd_print_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
37
{
38 39 40
	printk("\tmode | size | nlinks | first direct | mtime\n");
	if (stat_data_v1(ih)) {
		struct stat_data_v1 *sd = (struct stat_data_v1 *)item;
Linus Torvalds's avatar
Linus Torvalds committed
41

42
		printk("\t0%-6o | %6u | %2u | %d | %u\n", sd_v1_mode(sd),
43 44
		       sd_v1_size(sd), sd_v1_nlink(sd),
		       sd_v1_first_direct_byte(sd),
45
		       sd_v1_mtime(sd));
46 47
	} else {
		struct stat_data *sd = (struct stat_data *)item;
Linus Torvalds's avatar
Linus Torvalds committed
48

49
		printk("\t0%-6o | %6llu | %2u | %d | %u\n", sd_v2_mode(sd),
50
		       (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
51
		       sd_v2_rdev(sd), sd_v2_mtime(sd));
52
	}
Linus Torvalds's avatar
Linus Torvalds committed
53 54
}

55
static void sd_check_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
56
{
57
	/* unused */
Linus Torvalds's avatar
Linus Torvalds committed
58 59
}

60 61 62
static int sd_create_vi(struct virtual_node *vn,
			struct virtual_item *vi,
			int is_affected, int insert_size)
Linus Torvalds's avatar
Linus Torvalds committed
63
{
64 65
	vi->vi_index = TYPE_STAT_DATA;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
66 67
}

68 69
static int sd_check_left(struct virtual_item *vi, int free,
			 int start_skip, int end_skip)
Linus Torvalds's avatar
Linus Torvalds committed
70
{
71
	BUG_ON(start_skip || end_skip);
72
	return -1;
Linus Torvalds's avatar
Linus Torvalds committed
73 74
}

75
static int sd_check_right(struct virtual_item *vi, int free)
Linus Torvalds's avatar
Linus Torvalds committed
76
{
77
	return -1;
Linus Torvalds's avatar
Linus Torvalds committed
78 79
}

80
static int sd_part_size(struct virtual_item *vi, int first, int count)
Linus Torvalds's avatar
Linus Torvalds committed
81
{
82
	BUG_ON(count);
83
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
84 85
}

86
static int sd_unit_num(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
87
{
88
	return vi->vi_item_len - IH_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
89 90
}

91
static void sd_print_vi(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
92
{
93 94
	reiserfs_warning(NULL, "reiserfs-16100",
			 "STATDATA, index %d, type 0x%x, %h",
95
			 vi->vi_index, vi->vi_type, vi->vi_ih);
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98
}

static struct item_operations stat_data_ops = {
99 100 101 102 103 104 105 106 107 108 109 110
	.bytes_number = sd_bytes_number,
	.decrement_key = sd_decrement_key,
	.is_left_mergeable = sd_is_left_mergeable,
	.print_item = sd_print_item,
	.check_item = sd_check_item,

	.create_vi = sd_create_vi,
	.check_left = sd_check_left,
	.check_right = sd_check_right,
	.part_size = sd_part_size,
	.unit_num = sd_unit_num,
	.print_vi = sd_print_vi
Linus Torvalds's avatar
Linus Torvalds committed
111 112
};

113
/* direct item functions */
114
static int direct_bytes_number(struct item_head *ih, int block_size)
Linus Torvalds's avatar
Linus Torvalds committed
115
{
116
	return ih_item_len(ih);
Linus Torvalds's avatar
Linus Torvalds committed
117 118
}

119
/* FIXME: this should probably switch to indirect as well */
120
static void direct_decrement_key(struct cpu_key *key)
Linus Torvalds's avatar
Linus Torvalds committed
121
{
122 123 124
	cpu_key_k_offset_dec(key);
	if (cpu_key_k_offset(key) == 0)
		set_cpu_key_k_type(key, TYPE_STAT_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
125 126
}

127 128
static int direct_is_left_mergeable(struct reiserfs_key *key,
				    unsigned long bsize)
Linus Torvalds's avatar
Linus Torvalds committed
129
{
130 131
	int version = le_key_version(key);
	return ((le_key_k_offset(version, key) & (bsize - 1)) != 1);
Linus Torvalds's avatar
Linus Torvalds committed
132 133
}

134
static void direct_print_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
135
{
136
	int j = 0;
Linus Torvalds's avatar
Linus Torvalds committed
137

138
/*    return; */
139 140 141 142
	printk("\"");
	while (j < ih_item_len(ih))
		printk("%c", item[j++]);
	printk("\"\n");
Linus Torvalds's avatar
Linus Torvalds committed
143 144
}

145
static void direct_check_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
146
{
147
	/* unused */
Linus Torvalds's avatar
Linus Torvalds committed
148 149
}

150 151 152
static int direct_create_vi(struct virtual_node *vn,
			    struct virtual_item *vi,
			    int is_affected, int insert_size)
Linus Torvalds's avatar
Linus Torvalds committed
153
{
154 155
	vi->vi_index = TYPE_DIRECT;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
156 157
}

158 159
static int direct_check_left(struct virtual_item *vi, int free,
			     int start_skip, int end_skip)
Linus Torvalds's avatar
Linus Torvalds committed
160
{
161
	int bytes;
Linus Torvalds's avatar
Linus Torvalds committed
162

163 164
	bytes = free - free % 8;
	return bytes ? : -1;
Linus Torvalds's avatar
Linus Torvalds committed
165 166
}

167
static int direct_check_right(struct virtual_item *vi, int free)
Linus Torvalds's avatar
Linus Torvalds committed
168
{
169
	return direct_check_left(vi, free, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
170 171
}

172
static int direct_part_size(struct virtual_item *vi, int first, int count)
Linus Torvalds's avatar
Linus Torvalds committed
173
{
174
	return count;
Linus Torvalds's avatar
Linus Torvalds committed
175 176
}

177
static int direct_unit_num(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
178
{
179
	return vi->vi_item_len - IH_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
180 181
}

182
static void direct_print_vi(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
183
{
184 185
	reiserfs_warning(NULL, "reiserfs-16101",
			 "DIRECT, index %d, type 0x%x, %h",
186
			 vi->vi_index, vi->vi_type, vi->vi_ih);
Linus Torvalds's avatar
Linus Torvalds committed
187 188 189
}

static struct item_operations direct_ops = {
190 191 192 193 194 195 196 197 198 199 200 201
	.bytes_number = direct_bytes_number,
	.decrement_key = direct_decrement_key,
	.is_left_mergeable = direct_is_left_mergeable,
	.print_item = direct_print_item,
	.check_item = direct_check_item,

	.create_vi = direct_create_vi,
	.check_left = direct_check_left,
	.check_right = direct_check_right,
	.part_size = direct_part_size,
	.unit_num = direct_unit_num,
	.print_vi = direct_print_vi
Linus Torvalds's avatar
Linus Torvalds committed
202 203
};

204
/* indirect item functions */
205
static int indirect_bytes_number(struct item_head *ih, int block_size)
Linus Torvalds's avatar
Linus Torvalds committed
206
{
207
	return ih_item_len(ih) / UNFM_P_SIZE * block_size;
Linus Torvalds's avatar
Linus Torvalds committed
208 209
}

210
/* decrease offset, if it becomes 0, change type to stat data */
211
static void indirect_decrement_key(struct cpu_key *key)
Linus Torvalds's avatar
Linus Torvalds committed
212
{
213 214 215
	cpu_key_k_offset_dec(key);
	if (cpu_key_k_offset(key) == 0)
		set_cpu_key_k_type(key, TYPE_STAT_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
216 217
}

218
/* if it is not first item of the body, then it is mergeable */
219 220
static int indirect_is_left_mergeable(struct reiserfs_key *key,
				      unsigned long bsize)
Linus Torvalds's avatar
Linus Torvalds committed
221
{
222 223
	int version = le_key_version(key);
	return (le_key_k_offset(version, key) != 1);
Linus Torvalds's avatar
Linus Torvalds committed
224 225
}

226
/* printing of indirect item */
227
static void start_new_sequence(__u32 * start, int *len, __u32 new)
Linus Torvalds's avatar
Linus Torvalds committed
228
{
229 230
	*start = new;
	*len = 1;
Linus Torvalds's avatar
Linus Torvalds committed
231 232
}

233
static int sequence_finished(__u32 start, int *len, __u32 new)
Linus Torvalds's avatar
Linus Torvalds committed
234
{
235 236
	if (start == INT_MAX)
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
237

238 239 240 241 242 243 244 245 246
	if (start == 0 && new == 0) {
		(*len)++;
		return 0;
	}
	if (start != 0 && (start + *len) == new) {
		(*len)++;
		return 0;
	}
	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
247 248
}

249
static void print_sequence(__u32 start, int len)
Linus Torvalds's avatar
Linus Torvalds committed
250
{
251 252
	if (start == INT_MAX)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
253

254 255 256 257
	if (len == 1)
		printk(" %d", start);
	else
		printk(" %d(%d)", start, len);
Linus Torvalds's avatar
Linus Torvalds committed
258 259
}

260
static void indirect_print_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
261
{
262 263 264
	int j;
	__le32 *unp;
	__u32 prev = INT_MAX;
265
	int num = 0;
Linus Torvalds's avatar
Linus Torvalds committed
266

267
	unp = (__le32 *) item;
Linus Torvalds's avatar
Linus Torvalds committed
268

269
	if (ih_item_len(ih) % UNFM_P_SIZE)
270
		reiserfs_warning(NULL, "reiserfs-16102", "invalid item len");
Linus Torvalds's avatar
Linus Torvalds committed
271

272 273 274 275 276 277
	printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih));
	for (j = 0; j < I_UNFM_NUM(ih); j++) {
		if (sequence_finished(prev, &num, get_block_num(unp, j))) {
			print_sequence(prev, num);
			start_new_sequence(&prev, &num, get_block_num(unp, j));
		}
Linus Torvalds's avatar
Linus Torvalds committed
278
	}
279 280
	print_sequence(prev, num);
	printk("]\n");
Linus Torvalds's avatar
Linus Torvalds committed
281 282
}

283
static void indirect_check_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
284
{
285
	/* unused */
Linus Torvalds's avatar
Linus Torvalds committed
286 287
}

288 289 290
static int indirect_create_vi(struct virtual_node *vn,
			      struct virtual_item *vi,
			      int is_affected, int insert_size)
Linus Torvalds's avatar
Linus Torvalds committed
291
{
292 293
	vi->vi_index = TYPE_INDIRECT;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
294 295
}

296 297
static int indirect_check_left(struct virtual_item *vi, int free,
			       int start_skip, int end_skip)
Linus Torvalds's avatar
Linus Torvalds committed
298
{
299
	int bytes;
Linus Torvalds's avatar
Linus Torvalds committed
300

301 302
	bytes = free - free % UNFM_P_SIZE;
	return bytes ? : -1;
Linus Torvalds's avatar
Linus Torvalds committed
303 304
}

305
static int indirect_check_right(struct virtual_item *vi, int free)
Linus Torvalds's avatar
Linus Torvalds committed
306
{
307
	return indirect_check_left(vi, free, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
308 309
}

310 311 312 313
/*
 * return size in bytes of 'units' units. If first == 0 - calculate
 * from the head (left), otherwise - from tail (right)
 */
314
static int indirect_part_size(struct virtual_item *vi, int first, int units)
Linus Torvalds's avatar
Linus Torvalds committed
315
{
316
	/* unit of indirect item is byte (yet) */
317
	return units;
Linus Torvalds's avatar
Linus Torvalds committed
318 319
}

320
static int indirect_unit_num(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
321
{
322
	/* unit of indirect item is byte (yet) */
323
	return vi->vi_item_len - IH_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
324 325
}

326
static void indirect_print_vi(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
327
{
328 329
	reiserfs_warning(NULL, "reiserfs-16103",
			 "INDIRECT, index %d, type 0x%x, %h",
330
			 vi->vi_index, vi->vi_type, vi->vi_ih);
Linus Torvalds's avatar
Linus Torvalds committed
331 332 333
}

static struct item_operations indirect_ops = {
334 335 336 337 338 339 340 341 342 343 344 345
	.bytes_number = indirect_bytes_number,
	.decrement_key = indirect_decrement_key,
	.is_left_mergeable = indirect_is_left_mergeable,
	.print_item = indirect_print_item,
	.check_item = indirect_check_item,

	.create_vi = indirect_create_vi,
	.check_left = indirect_check_left,
	.check_right = indirect_check_right,
	.part_size = indirect_part_size,
	.unit_num = indirect_unit_num,
	.print_vi = indirect_print_vi
Linus Torvalds's avatar
Linus Torvalds committed
346 347
};

348
/* direntry functions */
349
static int direntry_bytes_number(struct item_head *ih, int block_size)
Linus Torvalds's avatar
Linus Torvalds committed
350
{
351
	reiserfs_warning(NULL, "vs-16090",
352 353
			 "bytes number is asked for direntry");
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
354 355
}

356
static void direntry_decrement_key(struct cpu_key *key)
Linus Torvalds's avatar
Linus Torvalds committed
357
{
358 359 360
	cpu_key_k_offset_dec(key);
	if (cpu_key_k_offset(key) == 0)
		set_cpu_key_k_type(key, TYPE_STAT_DATA);
Linus Torvalds's avatar
Linus Torvalds committed
361 362
}

363 364
static int direntry_is_left_mergeable(struct reiserfs_key *key,
				      unsigned long bsize)
Linus Torvalds's avatar
Linus Torvalds committed
365
{
366 367 368
	if (le32_to_cpu(key->u.k_offset_v1.k_offset) == DOT_OFFSET)
		return 0;
	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
369

370
}
Linus Torvalds's avatar
Linus Torvalds committed
371

372 373 374 375 376 377 378 379 380 381 382 383 384
static void direntry_print_item(struct item_head *ih, char *item)
{
	int i;
	int namelen;
	struct reiserfs_de_head *deh;
	char *name;
	static char namebuf[80];

	printk("\n # %-15s%-30s%-15s%-15s%-15s\n", "Name",
	       "Key of pointed object", "Hash", "Gen number", "Status");

	deh = (struct reiserfs_de_head *)item;

385
	for (i = 0; i < ih_entry_count(ih); i++, deh++) {
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
		namelen =
		    (i ? (deh_location(deh - 1)) : ih_item_len(ih)) -
		    deh_location(deh);
		name = item + deh_location(deh);
		if (name[namelen - 1] == 0)
			namelen = strlen(name);
		namebuf[0] = '"';
		if (namelen > sizeof(namebuf) - 3) {
			strncpy(namebuf + 1, name, sizeof(namebuf) - 3);
			namebuf[sizeof(namebuf) - 2] = '"';
			namebuf[sizeof(namebuf) - 1] = 0;
		} else {
			memcpy(namebuf + 1, name, namelen);
			namebuf[namelen + 1] = '"';
			namebuf[namelen + 2] = 0;
		}

403
		printk("%d:  %-15s%-15d%-15d%-15lld%-15lld(%s)\n",
404 405 406 407 408
		       i, namebuf,
		       deh_dir_id(deh), deh_objectid(deh),
		       GET_HASH_VALUE(deh_offset(deh)),
		       GET_GENERATION_NUMBER((deh_offset(deh))),
		       (de_hidden(deh)) ? "HIDDEN" : "VISIBLE");
Linus Torvalds's avatar
Linus Torvalds committed
409 410 411
	}
}

412
static void direntry_check_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
413
{
414 415
	int i;
	struct reiserfs_de_head *deh;
Linus Torvalds's avatar
Linus Torvalds committed
416

417
	/* unused */
418
	deh = (struct reiserfs_de_head *)item;
419
	for (i = 0; i < ih_entry_count(ih); i++, deh++) {
420 421
		;
	}
Linus Torvalds's avatar
Linus Torvalds committed
422 423 424 425 426 427
}

#define DIRENTRY_VI_FIRST_DIRENTRY_ITEM 1

/*
 * function returns old entry number in directory item in real node
428 429
 * using new entry number in virtual item in virtual node
 */
430 431
static inline int old_entry_num(int is_affected, int virtual_entry_num,
				int pos_in_item, int mode)
Linus Torvalds's avatar
Linus Torvalds committed
432
{
433 434
	if (mode == M_INSERT || mode == M_DELETE)
		return virtual_entry_num;
Linus Torvalds's avatar
Linus Torvalds committed
435

436 437 438
	if (!is_affected)
		/* cut or paste is applied to another item */
		return virtual_entry_num;
Linus Torvalds's avatar
Linus Torvalds committed
439

440 441
	if (virtual_entry_num < pos_in_item)
		return virtual_entry_num;
Linus Torvalds's avatar
Linus Torvalds committed
442

443 444
	if (mode == M_CUT)
		return virtual_entry_num + 1;
Linus Torvalds's avatar
Linus Torvalds committed
445

446 447 448
	RFALSE(mode != M_PASTE || virtual_entry_num == 0,
	       "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'",
	       mode);
Linus Torvalds's avatar
Linus Torvalds committed
449

450 451
	return virtual_entry_num - 1;
}
Linus Torvalds's avatar
Linus Torvalds committed
452

453 454 455 456 457
/*
 * Create an array of sizes of directory entries for virtual
 * item. Return space used by an item. FIXME: no control over
 * consuming of space used by this item handler
 */
458 459 460 461 462 463 464 465
static int direntry_create_vi(struct virtual_node *vn,
			      struct virtual_item *vi,
			      int is_affected, int insert_size)
{
	struct direntry_uarea *dir_u = vi->vi_uarea;
	int i, j;
	int size = sizeof(struct direntry_uarea);
	struct reiserfs_de_head *deh;
Linus Torvalds's avatar
Linus Torvalds committed
466

467 468
	vi->vi_index = TYPE_DIRENTRY;

469
	BUG_ON(!(vi->vi_ih) || !vi->vi_item);
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485

	dir_u->flags = 0;
	if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET)
		dir_u->flags |= DIRENTRY_VI_FIRST_DIRENTRY_ITEM;

	deh = (struct reiserfs_de_head *)(vi->vi_item);

	/* virtual directory item have this amount of entry after */
	dir_u->entry_count = ih_entry_count(vi->vi_ih) +
	    ((is_affected) ? ((vn->vn_mode == M_CUT) ? -1 :
			      (vn->vn_mode == M_PASTE ? 1 : 0)) : 0);

	for (i = 0; i < dir_u->entry_count; i++) {
		j = old_entry_num(is_affected, i, vn->vn_pos_in_item,
				  vn->vn_mode);
		dir_u->entry_sizes[i] =
486 487
		    (j ? deh_location(&deh[j - 1]) : ih_item_len(vi->vi_ih)) -
		    deh_location(&deh[j]) + DEH_SIZE;
488 489 490 491 492 493 494
	}

	size += (dir_u->entry_count * sizeof(short));

	/* set size of pasted entry */
	if (is_affected && vn->vn_mode == M_PASTE)
		dir_u->entry_sizes[vn->vn_pos_in_item] = insert_size;
Linus Torvalds's avatar
Linus Torvalds committed
495 496

#ifdef CONFIG_REISERFS_CHECK
497 498 499 500 501 502 503 504 505 506 507 508
	/* compare total size of entries with item length */
	{
		int k, l;

		l = 0;
		for (k = 0; k < dir_u->entry_count; k++)
			l += dir_u->entry_sizes[k];

		if (l + IH_SIZE != vi->vi_item_len +
		    ((is_affected
		      && (vn->vn_mode == M_PASTE
			  || vn->vn_mode == M_CUT)) ? insert_size : 0)) {
509 510 511
			reiserfs_panic(NULL, "vs-8025", "(mode==%c, "
				       "insert_size==%d), invalid length of "
				       "directory item",
512 513
				       vn->vn_mode, insert_size);
		}
Linus Torvalds's avatar
Linus Torvalds committed
514 515 516
	}
#endif

517
	return size;
Linus Torvalds's avatar
Linus Torvalds committed
518 519 520

}

521 522 523 524
/*
 * return number of entries which may fit into specified amount of
 * free space, or -1 if free space is not enough even for 1 entry
 */
525 526
static int direntry_check_left(struct virtual_item *vi, int free,
			       int start_skip, int end_skip)
Linus Torvalds's avatar
Linus Torvalds committed
527
{
528 529 530
	int i;
	int entries = 0;
	struct direntry_uarea *dir_u = vi->vi_uarea;
Linus Torvalds's avatar
Linus Torvalds committed
531

532
	for (i = start_skip; i < dir_u->entry_count - end_skip; i++) {
533
		/* i-th entry doesn't fit into the remaining free space */
534 535
		if (dir_u->entry_sizes[i] > free)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
536

537 538 539
		free -= dir_u->entry_sizes[i];
		entries++;
	}
Linus Torvalds's avatar
Linus Torvalds committed
540

541
	if (entries == dir_u->entry_count) {
542 543
		reiserfs_panic(NULL, "item_ops-1",
			       "free space %d, entry_count %d", free,
544 545
			       dir_u->entry_count);
	}
Linus Torvalds's avatar
Linus Torvalds committed
546

547 548 549 550
	/* "." and ".." can not be separated from each other */
	if (start_skip == 0 && (dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
	    && entries < 2)
		entries = 0;
Linus Torvalds's avatar
Linus Torvalds committed
551

552 553 554 555
	return entries ? : -1;
}

static int direntry_check_right(struct virtual_item *vi, int free)
Linus Torvalds's avatar
Linus Torvalds committed
556
{
557 558 559
	int i;
	int entries = 0;
	struct direntry_uarea *dir_u = vi->vi_uarea;
Linus Torvalds's avatar
Linus Torvalds committed
560

561
	for (i = dir_u->entry_count - 1; i >= 0; i--) {
562
		/* i-th entry doesn't fit into the remaining free space */
563 564
		if (dir_u->entry_sizes[i] > free)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
565

566 567 568
		free -= dir_u->entry_sizes[i];
		entries++;
	}
569
	BUG_ON(entries == dir_u->entry_count);
Linus Torvalds's avatar
Linus Torvalds committed
570

571 572 573 574 575 576 577
	/* "." and ".." can not be separated from each other */
	if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
	    && entries > dir_u->entry_count - 2)
		entries = dir_u->entry_count - 2;

	return entries ? : -1;
}
Linus Torvalds's avatar
Linus Torvalds committed
578 579

/* sum of entry sizes between from-th and to-th entries including both edges */
580
static int direntry_part_size(struct virtual_item *vi, int first, int count)
Linus Torvalds's avatar
Linus Torvalds committed
581
{
582 583 584
	int i, retval;
	int from, to;
	struct direntry_uarea *dir_u = vi->vi_uarea;
Linus Torvalds's avatar
Linus Torvalds committed
585

586 587 588 589 590 591
	retval = 0;
	if (first == 0)
		from = 0;
	else
		from = dir_u->entry_count - count;
	to = from + count - 1;
Linus Torvalds's avatar
Linus Torvalds committed
592

593 594
	for (i = from; i <= to; i++)
		retval += dir_u->entry_sizes[i];
Linus Torvalds's avatar
Linus Torvalds committed
595

596
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
597 598
}

599 600 601
static int direntry_unit_num(struct virtual_item *vi)
{
	struct direntry_uarea *dir_u = vi->vi_uarea;
Linus Torvalds's avatar
Linus Torvalds committed
602

603 604
	return dir_u->entry_count;
}
Linus Torvalds's avatar
Linus Torvalds committed
605

606
static void direntry_print_vi(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
607
{
608 609
	int i;
	struct direntry_uarea *dir_u = vi->vi_uarea;
Linus Torvalds's avatar
Linus Torvalds committed
610

611 612
	reiserfs_warning(NULL, "reiserfs-16104",
			 "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
613 614 615 616 617
			 vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags);
	printk("%d entries: ", dir_u->entry_count);
	for (i = 0; i < dir_u->entry_count; i++)
		printk("%d ", dir_u->entry_sizes[i]);
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
618 619 620
}

static struct item_operations direntry_ops = {
621 622 623 624 625 626 627 628 629 630 631 632
	.bytes_number = direntry_bytes_number,
	.decrement_key = direntry_decrement_key,
	.is_left_mergeable = direntry_is_left_mergeable,
	.print_item = direntry_print_item,
	.check_item = direntry_check_item,

	.create_vi = direntry_create_vi,
	.check_left = direntry_check_left,
	.check_right = direntry_check_right,
	.part_size = direntry_part_size,
	.unit_num = direntry_unit_num,
	.print_vi = direntry_print_vi
Linus Torvalds's avatar
Linus Torvalds committed
633 634
};

635
/* Error catching functions to catch errors caused by incorrect item types. */
636
static int errcatch_bytes_number(struct item_head *ih, int block_size)
Linus Torvalds's avatar
Linus Torvalds committed
637
{
638 639
	reiserfs_warning(NULL, "green-16001",
			 "Invalid item type observed, run fsck ASAP");
640
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
641 642
}

643
static void errcatch_decrement_key(struct cpu_key *key)
Linus Torvalds's avatar
Linus Torvalds committed
644
{
645 646
	reiserfs_warning(NULL, "green-16002",
			 "Invalid item type observed, run fsck ASAP");
Linus Torvalds's avatar
Linus Torvalds committed
647 648
}

649 650
static int errcatch_is_left_mergeable(struct reiserfs_key *key,
				      unsigned long bsize)
Linus Torvalds's avatar
Linus Torvalds committed
651
{
652 653
	reiserfs_warning(NULL, "green-16003",
			 "Invalid item type observed, run fsck ASAP");
654
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
655 656
}

657
static void errcatch_print_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
658
{
659 660
	reiserfs_warning(NULL, "green-16004",
			 "Invalid item type observed, run fsck ASAP");
Linus Torvalds's avatar
Linus Torvalds committed
661 662
}

663
static void errcatch_check_item(struct item_head *ih, char *item)
Linus Torvalds's avatar
Linus Torvalds committed
664
{
665 666
	reiserfs_warning(NULL, "green-16005",
			 "Invalid item type observed, run fsck ASAP");
Linus Torvalds's avatar
Linus Torvalds committed
667 668
}

669 670 671
static int errcatch_create_vi(struct virtual_node *vn,
			      struct virtual_item *vi,
			      int is_affected, int insert_size)
Linus Torvalds's avatar
Linus Torvalds committed
672
{
673 674
	reiserfs_warning(NULL, "green-16006",
			 "Invalid item type observed, run fsck ASAP");
675 676 677 678 679 680
	/*
	 * We might return -1 here as well, but it won't help as
	 * create_virtual_node() from where this operation is called
	 * from is of return type void.
	 */
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
681 682
}

683 684
static int errcatch_check_left(struct virtual_item *vi, int free,
			       int start_skip, int end_skip)
Linus Torvalds's avatar
Linus Torvalds committed
685
{
686 687
	reiserfs_warning(NULL, "green-16007",
			 "Invalid item type observed, run fsck ASAP");
688
	return -1;
Linus Torvalds's avatar
Linus Torvalds committed
689 690
}

691
static int errcatch_check_right(struct virtual_item *vi, int free)
Linus Torvalds's avatar
Linus Torvalds committed
692
{
693 694
	reiserfs_warning(NULL, "green-16008",
			 "Invalid item type observed, run fsck ASAP");
695
	return -1;
Linus Torvalds's avatar
Linus Torvalds committed
696 697
}

698
static int errcatch_part_size(struct virtual_item *vi, int first, int count)
Linus Torvalds's avatar
Linus Torvalds committed
699
{
700 701
	reiserfs_warning(NULL, "green-16009",
			 "Invalid item type observed, run fsck ASAP");
702
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
703 704
}

705
static int errcatch_unit_num(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
706
{
707 708
	reiserfs_warning(NULL, "green-16010",
			 "Invalid item type observed, run fsck ASAP");
709
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
710 711
}

712
static void errcatch_print_vi(struct virtual_item *vi)
Linus Torvalds's avatar
Linus Torvalds committed
713
{
714 715
	reiserfs_warning(NULL, "green-16011",
			 "Invalid item type observed, run fsck ASAP");
Linus Torvalds's avatar
Linus Torvalds committed
716 717 718
}

static struct item_operations errcatch_ops = {
719 720 721 722 723 724 725 726 727 728 729 730
	.bytes_number = errcatch_bytes_number,
	.decrement_key = errcatch_decrement_key,
	.is_left_mergeable = errcatch_is_left_mergeable,
	.print_item = errcatch_print_item,
	.check_item = errcatch_check_item,

	.create_vi = errcatch_create_vi,
	.check_left = errcatch_check_left,
	.check_right = errcatch_check_right,
	.part_size = errcatch_part_size,
	.unit_num = errcatch_unit_num,
	.print_vi = errcatch_print_vi
Linus Torvalds's avatar
Linus Torvalds committed
731 732 733
};

#if ! (TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3)
734
#error Item types must use disk-format assigned values.
Linus Torvalds's avatar
Linus Torvalds committed
735 736
#endif

737 738 739 740 741 742 743
struct item_operations *item_ops[TYPE_ANY + 1] = {
	&stat_data_ops,
	&indirect_ops,
	&direct_ops,
	&direntry_ops,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	&errcatch_ops		/* This is to catch errors with invalid type (15th entry for TYPE_ANY) */
Linus Torvalds's avatar
Linus Torvalds committed
744
};