162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/string.h>
662306a36Sopenharmony_ci#include <linux/time.h>
762306a36Sopenharmony_ci#include <linux/uuid.h>
862306a36Sopenharmony_ci#include "reiserfs.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* find where objectid map starts */
1162306a36Sopenharmony_ci#define objectid_map(s,rs) (old_format_only (s) ? \
1262306a36Sopenharmony_ci                         (__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
1362306a36Sopenharmony_ci			 (__le32 *)((rs) + 1))
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic void check_objectid_map(struct super_block *s, __le32 * map)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	if (le32_to_cpu(map[0]) != 1)
2062306a36Sopenharmony_ci		reiserfs_panic(s, "vs-15010", "map corrupted: %lx",
2162306a36Sopenharmony_ci			       (long unsigned int)le32_to_cpu(map[0]));
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	/* FIXME: add something else here */
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#else
2762306a36Sopenharmony_cistatic void check_objectid_map(struct super_block *s, __le32 * map)
2862306a36Sopenharmony_ci{;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci#endif
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * When we allocate objectids we allocate the first unused objectid.
3462306a36Sopenharmony_ci * Each sequence of objectids in use (the odd sequences) is followed
3562306a36Sopenharmony_ci * by a sequence of objectids not in use (the even sequences).  We
3662306a36Sopenharmony_ci * only need to record the last objectid in each of these sequences
3762306a36Sopenharmony_ci * (both the odd and even sequences) in order to fully define the
3862306a36Sopenharmony_ci * boundaries of the sequences.  A consequence of allocating the first
3962306a36Sopenharmony_ci * objectid not in use is that under most conditions this scheme is
4062306a36Sopenharmony_ci * extremely compact.  The exception is immediately after a sequence
4162306a36Sopenharmony_ci * of operations which deletes a large number of objects of
4262306a36Sopenharmony_ci * non-sequential objectids, and even then it will become compact
4362306a36Sopenharmony_ci * again as soon as more objects are created.  Note that many
4462306a36Sopenharmony_ci * interesting optimizations of layout could result from complicating
4562306a36Sopenharmony_ci * objectid assignment, but we have deferred making them for now.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* get unique object identifier */
4962306a36Sopenharmony_ci__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct super_block *s = th->t_super;
5262306a36Sopenharmony_ci	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
5362306a36Sopenharmony_ci	__le32 *map = objectid_map(s, rs);
5462306a36Sopenharmony_ci	__u32 unused_objectid;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	BUG_ON(!th->t_trans_id);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	check_objectid_map(s, map);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
6162306a36Sopenharmony_ci	/* comment needed -Hans */
6262306a36Sopenharmony_ci	unused_objectid = le32_to_cpu(map[1]);
6362306a36Sopenharmony_ci	if (unused_objectid == U32_MAX) {
6462306a36Sopenharmony_ci		reiserfs_warning(s, "reiserfs-15100", "no more object ids");
6562306a36Sopenharmony_ci		reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
6662306a36Sopenharmony_ci		return 0;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/*
7062306a36Sopenharmony_ci	 * This incrementation allocates the first unused objectid. That
7162306a36Sopenharmony_ci	 * is to say, the first entry on the objectid map is the first
7262306a36Sopenharmony_ci	 * unused objectid, and by incrementing it we use it.  See below
7362306a36Sopenharmony_ci	 * where we check to see if we eliminated a sequence of unused
7462306a36Sopenharmony_ci	 * objectids....
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	map[1] = cpu_to_le32(unused_objectid + 1);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * Now we check to see if we eliminated the last remaining member of
8062306a36Sopenharmony_ci	 * the first even sequence (and can eliminate the sequence by
8162306a36Sopenharmony_ci	 * eliminating its last objectid from oids), and can collapse the
8262306a36Sopenharmony_ci	 * first two odd sequences into one sequence.  If so, then the net
8362306a36Sopenharmony_ci	 * result is to eliminate a pair of objectids from oids.  We do this
8462306a36Sopenharmony_ci	 * by shifting the entire map to the left.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
8762306a36Sopenharmony_ci		memmove(map + 1, map + 3,
8862306a36Sopenharmony_ci			(sb_oid_cursize(rs) - 3) * sizeof(__u32));
8962306a36Sopenharmony_ci		set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
9362306a36Sopenharmony_ci	return unused_objectid;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* makes object identifier unused */
9762306a36Sopenharmony_civoid reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
9862306a36Sopenharmony_ci			       __u32 objectid_to_release)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct super_block *s = th->t_super;
10162306a36Sopenharmony_ci	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
10262306a36Sopenharmony_ci	__le32 *map = objectid_map(s, rs);
10362306a36Sopenharmony_ci	int i = 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	BUG_ON(!th->t_trans_id);
10662306a36Sopenharmony_ci	/*return; */
10762306a36Sopenharmony_ci	check_objectid_map(s, map);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
11062306a36Sopenharmony_ci	journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/*
11362306a36Sopenharmony_ci	 * start at the beginning of the objectid map (i = 0) and go to
11462306a36Sopenharmony_ci	 * the end of it (i = disk_sb->s_oid_cursize).  Linear search is
11562306a36Sopenharmony_ci	 * what we use, though it is possible that binary search would be
11662306a36Sopenharmony_ci	 * more efficient after performing lots of deletions (which is
11762306a36Sopenharmony_ci	 * when oids is large.)  We only check even i's.
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	while (i < sb_oid_cursize(rs)) {
12062306a36Sopenharmony_ci		if (objectid_to_release == le32_to_cpu(map[i])) {
12162306a36Sopenharmony_ci			/* This incrementation unallocates the objectid. */
12262306a36Sopenharmony_ci			le32_add_cpu(&map[i], 1);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci			/*
12562306a36Sopenharmony_ci			 * Did we unallocate the last member of an
12662306a36Sopenharmony_ci			 * odd sequence, and can shrink oids?
12762306a36Sopenharmony_ci			 */
12862306a36Sopenharmony_ci			if (map[i] == map[i + 1]) {
12962306a36Sopenharmony_ci				/* shrink objectid map */
13062306a36Sopenharmony_ci				memmove(map + i, map + i + 2,
13162306a36Sopenharmony_ci					(sb_oid_cursize(rs) - i -
13262306a36Sopenharmony_ci					 2) * sizeof(__u32));
13362306a36Sopenharmony_ci				set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci				RFALSE(sb_oid_cursize(rs) < 2 ||
13662306a36Sopenharmony_ci				       sb_oid_cursize(rs) > sb_oid_maxsize(rs),
13762306a36Sopenharmony_ci				       "vs-15005: objectid map corrupted cur_size == %d (max == %d)",
13862306a36Sopenharmony_ci				       sb_oid_cursize(rs), sb_oid_maxsize(rs));
13962306a36Sopenharmony_ci			}
14062306a36Sopenharmony_ci			return;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		if (objectid_to_release > le32_to_cpu(map[i]) &&
14462306a36Sopenharmony_ci		    objectid_to_release < le32_to_cpu(map[i + 1])) {
14562306a36Sopenharmony_ci			/* size of objectid map is not changed */
14662306a36Sopenharmony_ci			if (objectid_to_release + 1 == le32_to_cpu(map[i + 1])) {
14762306a36Sopenharmony_ci				le32_add_cpu(&map[i + 1], -1);
14862306a36Sopenharmony_ci				return;
14962306a36Sopenharmony_ci			}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci			/*
15262306a36Sopenharmony_ci			 * JDM comparing two little-endian values for
15362306a36Sopenharmony_ci			 * equality -- safe
15462306a36Sopenharmony_ci			 */
15562306a36Sopenharmony_ci			/*
15662306a36Sopenharmony_ci			 * objectid map must be expanded, but
15762306a36Sopenharmony_ci			 * there is no space
15862306a36Sopenharmony_ci			 */
15962306a36Sopenharmony_ci			if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
16062306a36Sopenharmony_ci				PROC_INFO_INC(s, leaked_oid);
16162306a36Sopenharmony_ci				return;
16262306a36Sopenharmony_ci			}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci			/* expand the objectid map */
16562306a36Sopenharmony_ci			memmove(map + i + 3, map + i + 1,
16662306a36Sopenharmony_ci				(sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
16762306a36Sopenharmony_ci			map[i + 1] = cpu_to_le32(objectid_to_release);
16862306a36Sopenharmony_ci			map[i + 2] = cpu_to_le32(objectid_to_release + 1);
16962306a36Sopenharmony_ci			set_sb_oid_cursize(rs, sb_oid_cursize(rs) + 2);
17062306a36Sopenharmony_ci			return;
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci		i += 2;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	reiserfs_error(s, "vs-15011", "tried to free free object id (%lu)",
17662306a36Sopenharmony_ci		       (long unsigned)objectid_to_release);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciint reiserfs_convert_objectid_map_v1(struct super_block *s)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK(s);
18262306a36Sopenharmony_ci	int cur_size = sb_oid_cursize(disk_sb);
18362306a36Sopenharmony_ci	int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2;
18462306a36Sopenharmony_ci	int old_max = sb_oid_maxsize(disk_sb);
18562306a36Sopenharmony_ci	struct reiserfs_super_block_v1 *disk_sb_v1;
18662306a36Sopenharmony_ci	__le32 *objectid_map;
18762306a36Sopenharmony_ci	int i;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	disk_sb_v1 =
19062306a36Sopenharmony_ci	    (struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
19162306a36Sopenharmony_ci	objectid_map = (__le32 *) (disk_sb_v1 + 1);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (cur_size > new_size) {
19462306a36Sopenharmony_ci		/*
19562306a36Sopenharmony_ci		 * mark everyone used that was listed as free at
19662306a36Sopenharmony_ci		 * the end of the objectid map
19762306a36Sopenharmony_ci		 */
19862306a36Sopenharmony_ci		objectid_map[new_size - 1] = objectid_map[cur_size - 1];
19962306a36Sopenharmony_ci		set_sb_oid_cursize(disk_sb, new_size);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci	/* move the smaller objectid map past the end of the new super */
20262306a36Sopenharmony_ci	for (i = new_size - 1; i >= 0; i--) {
20362306a36Sopenharmony_ci		objectid_map[i + (old_max - new_size)] = objectid_map[i];
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* set the max size so we don't overflow later */
20762306a36Sopenharmony_ci	set_sb_oid_maxsize(disk_sb, new_size);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Zero out label and generate random UUID */
21062306a36Sopenharmony_ci	memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label));
21162306a36Sopenharmony_ci	generate_random_uuid(disk_sb->s_uuid);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* finally, zero out the unused chunk of the new super */
21462306a36Sopenharmony_ci	memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused));
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
217