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