xref: /linux/fs/reiserfs/objectid.c (revision b746a1a2860f4a918f32d10dc569115d282aaf2f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
31da177e4SLinus Torvalds  */
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds #include <linux/string.h>
61da177e4SLinus Torvalds #include <linux/time.h>
78da4b8c4SAndy Shevchenko #include <linux/uuid.h>
8f466c6fdSAl Viro #include "reiserfs.h"
91da177e4SLinus Torvalds 
10098297b2SJeff Mahoney /* find where objectid map starts */
111da177e4SLinus Torvalds #define objectid_map(s,rs) (old_format_only (s) ? \
123e8962beSAl Viro                          (__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
133e8962beSAl Viro 			 (__le32 *)((rs) + 1))
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
161da177e4SLinus Torvalds 
check_objectid_map(struct super_block * s,__le32 * map)173e8962beSAl Viro static void check_objectid_map(struct super_block *s, __le32 * map)
181da177e4SLinus Torvalds {
191da177e4SLinus Torvalds 	if (le32_to_cpu(map[0]) != 1)
20c3a9c210SJeff Mahoney 		reiserfs_panic(s, "vs-15010", "map corrupted: %lx",
211da177e4SLinus Torvalds 			       (long unsigned int)le32_to_cpu(map[0]));
221da177e4SLinus Torvalds 
23098297b2SJeff Mahoney 	/* FIXME: add something else here */
241da177e4SLinus Torvalds }
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #else
check_objectid_map(struct super_block * s,__le32 * map)273e8962beSAl Viro static void check_objectid_map(struct super_block *s, __le32 * map)
28bd4c625cSLinus Torvalds {;
29bd4c625cSLinus Torvalds }
301da177e4SLinus Torvalds #endif
311da177e4SLinus Torvalds 
32098297b2SJeff Mahoney /*
33098297b2SJeff Mahoney  * When we allocate objectids we allocate the first unused objectid.
34098297b2SJeff Mahoney  * Each sequence of objectids in use (the odd sequences) is followed
35098297b2SJeff Mahoney  * by a sequence of objectids not in use (the even sequences).  We
36098297b2SJeff Mahoney  * only need to record the last objectid in each of these sequences
37098297b2SJeff Mahoney  * (both the odd and even sequences) in order to fully define the
38098297b2SJeff Mahoney  * boundaries of the sequences.  A consequence of allocating the first
39098297b2SJeff Mahoney  * objectid not in use is that under most conditions this scheme is
40098297b2SJeff Mahoney  * extremely compact.  The exception is immediately after a sequence
41098297b2SJeff Mahoney  * of operations which deletes a large number of objects of
42098297b2SJeff Mahoney  * non-sequential objectids, and even then it will become compact
43098297b2SJeff Mahoney  * again as soon as more objects are created.  Note that many
44098297b2SJeff Mahoney  * interesting optimizations of layout could result from complicating
45098297b2SJeff Mahoney  * objectid assignment, but we have deferred making them for now.
46098297b2SJeff Mahoney  */
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /* get unique object identifier */
reiserfs_get_unused_objectid(struct reiserfs_transaction_handle * th)491da177e4SLinus Torvalds __u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
501da177e4SLinus Torvalds {
511da177e4SLinus Torvalds 	struct super_block *s = th->t_super;
521da177e4SLinus Torvalds 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
533e8962beSAl Viro 	__le32 *map = objectid_map(s, rs);
541da177e4SLinus Torvalds 	__u32 unused_objectid;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	BUG_ON(!th->t_trans_id);
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	check_objectid_map(s, map);
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
611da177e4SLinus Torvalds 	/* comment needed -Hans */
621da177e4SLinus Torvalds 	unused_objectid = le32_to_cpu(map[1]);
631da177e4SLinus Torvalds 	if (unused_objectid == U32_MAX) {
6445b03d5eSJeff Mahoney 		reiserfs_warning(s, "reiserfs-15100", "no more object ids");
651da177e4SLinus Torvalds 		reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
661da177e4SLinus Torvalds 		return 0;
671da177e4SLinus Torvalds 	}
681da177e4SLinus Torvalds 
69098297b2SJeff Mahoney 	/*
70098297b2SJeff Mahoney 	 * This incrementation allocates the first unused objectid. That
71098297b2SJeff Mahoney 	 * is to say, the first entry on the objectid map is the first
72098297b2SJeff Mahoney 	 * unused objectid, and by incrementing it we use it.  See below
73098297b2SJeff Mahoney 	 * where we check to see if we eliminated a sequence of unused
74098297b2SJeff Mahoney 	 * objectids....
75098297b2SJeff Mahoney 	 */
761da177e4SLinus Torvalds 	map[1] = cpu_to_le32(unused_objectid + 1);
771da177e4SLinus Torvalds 
78098297b2SJeff Mahoney 	/*
79098297b2SJeff Mahoney 	 * Now we check to see if we eliminated the last remaining member of
80098297b2SJeff Mahoney 	 * the first even sequence (and can eliminate the sequence by
81098297b2SJeff Mahoney 	 * eliminating its last objectid from oids), and can collapse the
82098297b2SJeff Mahoney 	 * first two odd sequences into one sequence.  If so, then the net
83098297b2SJeff Mahoney 	 * result is to eliminate a pair of objectids from oids.  We do this
84098297b2SJeff Mahoney 	 * by shifting the entire map to the left.
85098297b2SJeff Mahoney 	 */
861da177e4SLinus Torvalds 	if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
87bd4c625cSLinus Torvalds 		memmove(map + 1, map + 3,
88bd4c625cSLinus Torvalds 			(sb_oid_cursize(rs) - 3) * sizeof(__u32));
891da177e4SLinus Torvalds 		set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
901da177e4SLinus Torvalds 	}
911da177e4SLinus Torvalds 
9209f1b80bSJeff Mahoney 	journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
931da177e4SLinus Torvalds 	return unused_objectid;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /* makes object identifier unused */
reiserfs_release_objectid(struct reiserfs_transaction_handle * th,__u32 objectid_to_release)971da177e4SLinus Torvalds void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
981da177e4SLinus Torvalds 			       __u32 objectid_to_release)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	struct super_block *s = th->t_super;
1011da177e4SLinus Torvalds 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
1023e8962beSAl Viro 	__le32 *map = objectid_map(s, rs);
1031da177e4SLinus Torvalds 	int i = 0;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	BUG_ON(!th->t_trans_id);
106098297b2SJeff Mahoney 	/*return; */
1071da177e4SLinus Torvalds 	check_objectid_map(s, map);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
11009f1b80bSJeff Mahoney 	journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
1111da177e4SLinus Torvalds 
112098297b2SJeff Mahoney 	/*
113098297b2SJeff Mahoney 	 * start at the beginning of the objectid map (i = 0) and go to
114098297b2SJeff Mahoney 	 * the end of it (i = disk_sb->s_oid_cursize).  Linear search is
115098297b2SJeff Mahoney 	 * what we use, though it is possible that binary search would be
116098297b2SJeff Mahoney 	 * more efficient after performing lots of deletions (which is
117098297b2SJeff Mahoney 	 * when oids is large.)  We only check even i's.
118098297b2SJeff Mahoney 	 */
1191da177e4SLinus Torvalds 	while (i < sb_oid_cursize(rs)) {
1201da177e4SLinus Torvalds 		if (objectid_to_release == le32_to_cpu(map[i])) {
1211da177e4SLinus Torvalds 			/* This incrementation unallocates the objectid. */
1229e902df6SMarcin Slusarz 			le32_add_cpu(&map[i], 1);
1231da177e4SLinus Torvalds 
124098297b2SJeff Mahoney 			/*
125098297b2SJeff Mahoney 			 * Did we unallocate the last member of an
126098297b2SJeff Mahoney 			 * odd sequence, and can shrink oids?
127098297b2SJeff Mahoney 			 */
1281da177e4SLinus Torvalds 			if (map[i] == map[i + 1]) {
1291da177e4SLinus Torvalds 				/* shrink objectid map */
1301da177e4SLinus Torvalds 				memmove(map + i, map + i + 2,
131bd4c625cSLinus Torvalds 					(sb_oid_cursize(rs) - i -
132bd4c625cSLinus Torvalds 					 2) * sizeof(__u32));
1331da177e4SLinus Torvalds 				set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 				RFALSE(sb_oid_cursize(rs) < 2 ||
1361da177e4SLinus Torvalds 				       sb_oid_cursize(rs) > sb_oid_maxsize(rs),
1371da177e4SLinus Torvalds 				       "vs-15005: objectid map corrupted cur_size == %d (max == %d)",
1381da177e4SLinus Torvalds 				       sb_oid_cursize(rs), sb_oid_maxsize(rs));
1391da177e4SLinus Torvalds 			}
1401da177e4SLinus Torvalds 			return;
1411da177e4SLinus Torvalds 		}
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 		if (objectid_to_release > le32_to_cpu(map[i]) &&
1441da177e4SLinus Torvalds 		    objectid_to_release < le32_to_cpu(map[i + 1])) {
1451da177e4SLinus Torvalds 			/* size of objectid map is not changed */
1461da177e4SLinus Torvalds 			if (objectid_to_release + 1 == le32_to_cpu(map[i + 1])) {
1479e902df6SMarcin Slusarz 				le32_add_cpu(&map[i + 1], -1);
1481da177e4SLinus Torvalds 				return;
1491da177e4SLinus Torvalds 			}
1501da177e4SLinus Torvalds 
151098297b2SJeff Mahoney 			/*
152098297b2SJeff Mahoney 			 * JDM comparing two little-endian values for
153098297b2SJeff Mahoney 			 * equality -- safe
154098297b2SJeff Mahoney 			 */
155098297b2SJeff Mahoney 			/*
156098297b2SJeff Mahoney 			 * objectid map must be expanded, but
157098297b2SJeff Mahoney 			 * there is no space
158098297b2SJeff Mahoney 			 */
1591da177e4SLinus Torvalds 			if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
1601da177e4SLinus Torvalds 				PROC_INFO_INC(s, leaked_oid);
1611da177e4SLinus Torvalds 				return;
1621da177e4SLinus Torvalds 			}
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 			/* expand the objectid map */
1651da177e4SLinus Torvalds 			memmove(map + i + 3, map + i + 1,
1661da177e4SLinus Torvalds 				(sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
1671da177e4SLinus Torvalds 			map[i + 1] = cpu_to_le32(objectid_to_release);
1681da177e4SLinus Torvalds 			map[i + 2] = cpu_to_le32(objectid_to_release + 1);
1691da177e4SLinus Torvalds 			set_sb_oid_cursize(rs, sb_oid_cursize(rs) + 2);
1701da177e4SLinus Torvalds 			return;
1711da177e4SLinus Torvalds 		}
1721da177e4SLinus Torvalds 		i += 2;
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 
1750030b645SJeff Mahoney 	reiserfs_error(s, "vs-15011", "tried to free free object id (%lu)",
1761da177e4SLinus Torvalds 		       (long unsigned)objectid_to_release);
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
reiserfs_convert_objectid_map_v1(struct super_block * s)179bd4c625cSLinus Torvalds int reiserfs_convert_objectid_map_v1(struct super_block *s)
180bd4c625cSLinus Torvalds {
1811da177e4SLinus Torvalds 	struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK(s);
1821da177e4SLinus Torvalds 	int cur_size = sb_oid_cursize(disk_sb);
1831da177e4SLinus Torvalds 	int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2;
1841da177e4SLinus Torvalds 	int old_max = sb_oid_maxsize(disk_sb);
1851da177e4SLinus Torvalds 	struct reiserfs_super_block_v1 *disk_sb_v1;
186*4a70aebbSzhengbin 	__le32 *objectid_map;
1871da177e4SLinus Torvalds 	int i;
1881da177e4SLinus Torvalds 
189bd4c625cSLinus Torvalds 	disk_sb_v1 =
190bd4c625cSLinus Torvalds 	    (struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
1913e8962beSAl Viro 	objectid_map = (__le32 *) (disk_sb_v1 + 1);
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	if (cur_size > new_size) {
194098297b2SJeff Mahoney 		/*
195098297b2SJeff Mahoney 		 * mark everyone used that was listed as free at
196098297b2SJeff Mahoney 		 * the end of the objectid map
1971da177e4SLinus Torvalds 		 */
1981da177e4SLinus Torvalds 		objectid_map[new_size - 1] = objectid_map[cur_size - 1];
1991da177e4SLinus Torvalds 		set_sb_oid_cursize(disk_sb, new_size);
2001da177e4SLinus Torvalds 	}
2011da177e4SLinus Torvalds 	/* move the smaller objectid map past the end of the new super */
2021da177e4SLinus Torvalds 	for (i = new_size - 1; i >= 0; i--) {
2031da177e4SLinus Torvalds 		objectid_map[i + (old_max - new_size)] = objectid_map[i];
2041da177e4SLinus Torvalds 	}
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	/* set the max size so we don't overflow later */
2071da177e4SLinus Torvalds 	set_sb_oid_maxsize(disk_sb, new_size);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* Zero out label and generate random UUID */
2101da177e4SLinus Torvalds 	memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label));
2111da177e4SLinus Torvalds 	generate_random_uuid(disk_sb->s_uuid);
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	/* finally, zero out the unused chunk of the new super */
2141da177e4SLinus Torvalds 	memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused));
2151da177e4SLinus Torvalds 	return 0;
2161da177e4SLinus Torvalds }
217