Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 1 | /* |
| 2 | * icount.c --- an efficient inode count abstraction |
| 3 | * |
| 4 | * Copyright (C) 1997 Theodore Ts'o. |
| 5 | * |
| 6 | * %Begin-Header% |
Theodore Ts'o | 543547a | 2010-05-17 21:31:56 -0400 | [diff] [blame] | 7 | * This file may be redistributed under the terms of the GNU Library |
| 8 | * General Public License, version 2. |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 9 | * %End-Header% |
| 10 | */ |
| 11 | |
Theodore Ts'o | d1154eb | 2011-09-18 17:34:37 -0400 | [diff] [blame] | 12 | #include "config.h" |
Theodore Ts'o | 4cbe8af | 1997-08-10 23:07:40 +0000 | [diff] [blame] | 13 | #if HAVE_UNISTD_H |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 14 | #include <unistd.h> |
Theodore Ts'o | 4cbe8af | 1997-08-10 23:07:40 +0000 | [diff] [blame] | 15 | #endif |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 16 | #include <string.h> |
| 17 | #include <stdio.h> |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 18 | #include <sys/stat.h> |
| 19 | #include <fcntl.h> |
| 20 | #include <errno.h> |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 21 | |
Theodore Ts'o | b5abe6f | 1998-01-19 14:47:53 +0000 | [diff] [blame] | 22 | #include "ext2_fs.h" |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 23 | #include "ext2fs.h" |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 24 | #include "tdb.h" |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 25 | |
| 26 | /* |
| 27 | * The data storage strategy used by icount relies on the observation |
| 28 | * that most inode counts are either zero (for non-allocated inodes), |
| 29 | * one (for most files), and only a few that are two or more |
| 30 | * (directories and files that are linked to more than one directory). |
| 31 | * |
| 32 | * Also, e2fsck tends to load the icount data sequentially. |
| 33 | * |
| 34 | * So, we use an inode bitmap to indicate which inodes have a count of |
| 35 | * one, and then use a sorted list to store the counts for inodes |
| 36 | * which are greater than one. |
| 37 | * |
| 38 | * We also use an optional bitmap to indicate which inodes are already |
| 39 | * in the sorted list, to speed up the use of this abstraction by |
| 40 | * e2fsck's pass 2. Pass 2 increments inode counts as it finds them, |
| 41 | * so this extra bitmap avoids searching the sorted list to see if a |
| 42 | * particular inode is on the sorted list already. |
| 43 | */ |
| 44 | |
| 45 | struct ext2_icount_el { |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 46 | ext2_ino_t ino; |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 47 | __u32 count; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 48 | }; |
| 49 | |
| 50 | struct ext2_icount { |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 51 | errcode_t magic; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 52 | ext2fs_inode_bitmap single; |
| 53 | ext2fs_inode_bitmap multiple; |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 54 | ext2_ino_t count; |
| 55 | ext2_ino_t size; |
| 56 | ext2_ino_t num_inodes; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 57 | ext2_ino_t cursor; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 58 | struct ext2_icount_el *list; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 59 | struct ext2_icount_el *last_lookup; |
| 60 | char *tdb_fn; |
| 61 | TDB_CONTEXT *tdb; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 62 | }; |
| 63 | |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 64 | /* |
| 65 | * We now use a 32-bit counter field because it doesn't cost us |
| 66 | * anything extra for the in-memory data structure, due to alignment |
| 67 | * padding. But there's no point changing the interface if most of |
| 68 | * the time we only care if the number is bigger than 65,000 or not. |
| 69 | * So use the following translation function to return a 16-bit count. |
| 70 | */ |
| 71 | #define icount_16_xlate(x) (((x) > 65500) ? 65500 : (x)) |
| 72 | |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 73 | void ext2fs_free_icount(ext2_icount_t icount) |
| 74 | { |
| 75 | if (!icount) |
| 76 | return; |
| 77 | |
| 78 | icount->magic = 0; |
| 79 | if (icount->list) |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 80 | ext2fs_free_mem(&icount->list); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 81 | if (icount->single) |
| 82 | ext2fs_free_inode_bitmap(icount->single); |
| 83 | if (icount->multiple) |
| 84 | ext2fs_free_inode_bitmap(icount->multiple); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 85 | if (icount->tdb) |
| 86 | tdb_close(icount->tdb); |
| 87 | if (icount->tdb_fn) { |
| 88 | unlink(icount->tdb_fn); |
| 89 | free(icount->tdb_fn); |
| 90 | } |
| 91 | |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 92 | ext2fs_free_mem(&icount); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 93 | } |
| 94 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 95 | static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret) |
| 96 | { |
| 97 | ext2_icount_t icount; |
| 98 | errcode_t retval; |
| 99 | |
| 100 | *ret = 0; |
| 101 | |
| 102 | retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount); |
| 103 | if (retval) |
| 104 | return retval; |
| 105 | memset(icount, 0, sizeof(struct ext2_icount)); |
| 106 | |
Lukas Czerner | 9288e3b | 2011-12-16 17:31:07 -0500 | [diff] [blame] | 107 | retval = ext2fs_allocate_inode_bitmap(fs, "icount", &icount->single); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 108 | if (retval) |
| 109 | goto errout; |
| 110 | |
| 111 | if (flags & EXT2_ICOUNT_OPT_INCREMENT) { |
Lukas Czerner | 9288e3b | 2011-12-16 17:31:07 -0500 | [diff] [blame] | 112 | retval = ext2fs_allocate_inode_bitmap(fs, "icount_inc", |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 113 | &icount->multiple); |
| 114 | if (retval) |
| 115 | goto errout; |
| 116 | } else |
| 117 | icount->multiple = 0; |
| 118 | |
| 119 | icount->magic = EXT2_ET_MAGIC_ICOUNT; |
| 120 | icount->num_inodes = fs->super->s_inodes_count; |
| 121 | |
| 122 | *ret = icount; |
| 123 | return 0; |
| 124 | |
| 125 | errout: |
| 126 | ext2fs_free_icount(icount); |
| 127 | return(retval); |
| 128 | } |
| 129 | |
| 130 | struct uuid { |
| 131 | __u32 time_low; |
| 132 | __u16 time_mid; |
| 133 | __u16 time_hi_and_version; |
| 134 | __u16 clock_seq; |
| 135 | __u8 node[6]; |
| 136 | }; |
| 137 | |
| 138 | static void unpack_uuid(void *in, struct uuid *uu) |
| 139 | { |
| 140 | __u8 *ptr = in; |
| 141 | __u32 tmp; |
| 142 | |
| 143 | tmp = *ptr++; |
| 144 | tmp = (tmp << 8) | *ptr++; |
| 145 | tmp = (tmp << 8) | *ptr++; |
| 146 | tmp = (tmp << 8) | *ptr++; |
| 147 | uu->time_low = tmp; |
| 148 | |
| 149 | tmp = *ptr++; |
| 150 | tmp = (tmp << 8) | *ptr++; |
| 151 | uu->time_mid = tmp; |
| 152 | |
| 153 | tmp = *ptr++; |
| 154 | tmp = (tmp << 8) | *ptr++; |
| 155 | uu->time_hi_and_version = tmp; |
| 156 | |
| 157 | tmp = *ptr++; |
| 158 | tmp = (tmp << 8) | *ptr++; |
| 159 | uu->clock_seq = tmp; |
| 160 | |
| 161 | memcpy(uu->node, ptr, 6); |
| 162 | } |
| 163 | |
| 164 | static void uuid_unparse(void *uu, char *out) |
| 165 | { |
| 166 | struct uuid uuid; |
| 167 | |
| 168 | unpack_uuid(uu, &uuid); |
| 169 | sprintf(out, |
| 170 | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
| 171 | uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, |
| 172 | uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, |
| 173 | uuid.node[0], uuid.node[1], uuid.node[2], |
| 174 | uuid.node[3], uuid.node[4], uuid.node[5]); |
| 175 | } |
| 176 | |
| 177 | errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, |
| 178 | int flags, ext2_icount_t *ret) |
| 179 | { |
| 180 | ext2_icount_t icount; |
| 181 | errcode_t retval; |
| 182 | char *fn, uuid[40]; |
Theodore Ts'o | 4e523bb | 2011-11-29 11:24:52 -0500 | [diff] [blame] | 183 | ext2_ino_t num_inodes; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 184 | int fd; |
| 185 | |
| 186 | retval = alloc_icount(fs, flags, &icount); |
| 187 | if (retval) |
| 188 | return retval; |
| 189 | |
| 190 | retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn); |
| 191 | if (retval) |
| 192 | goto errout; |
| 193 | uuid_unparse(fs->super->s_uuid, uuid); |
| 194 | sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); |
| 195 | fd = mkstemp(fn); |
| 196 | |
Theodore Ts'o | 4e523bb | 2011-11-29 11:24:52 -0500 | [diff] [blame] | 197 | /* |
| 198 | * This is an overestimate of the size that we will need; the |
| 199 | * ideal value is the number of used inodes with a count |
| 200 | * greater than 1. OTOH the times when we really need this is |
| 201 | * with the backup programs that use lots of hard links, in |
| 202 | * which case the number of inodes in use approaches the ideal |
| 203 | * value. |
| 204 | */ |
| 205 | num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count; |
| 206 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 207 | icount->tdb_fn = fn; |
Theodore Ts'o | 4e523bb | 2011-11-29 11:24:52 -0500 | [diff] [blame] | 208 | icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC, |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 209 | O_RDWR | O_CREAT | O_TRUNC, 0600); |
| 210 | if (icount->tdb) { |
| 211 | close(fd); |
| 212 | *ret = icount; |
| 213 | return 0; |
| 214 | } |
| 215 | |
| 216 | retval = errno; |
| 217 | close(fd); |
| 218 | |
| 219 | errout: |
| 220 | ext2fs_free_icount(icount); |
| 221 | return(retval); |
| 222 | } |
| 223 | |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 224 | errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size, |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 225 | ext2_icount_t hint, ext2_icount_t *ret) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 226 | { |
| 227 | ext2_icount_t icount; |
| 228 | errcode_t retval; |
| 229 | size_t bytes; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 230 | ext2_ino_t i; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 231 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 232 | if (hint) { |
| 233 | EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT); |
| 234 | if (hint->size > size) |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 235 | size = (size_t) hint->size; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 236 | } |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 237 | |
| 238 | retval = alloc_icount(fs, flags, &icount); |
Theodore Ts'o | 7b4e453 | 1997-10-26 03:41:24 +0000 | [diff] [blame] | 239 | if (retval) |
| 240 | return retval; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 241 | |
| 242 | if (size) { |
| 243 | icount->size = size; |
| 244 | } else { |
| 245 | /* |
| 246 | * Figure out how many special case inode counts we will |
| 247 | * have. We know we will need one for each directory; |
| 248 | * we also need to reserve some extra room for file links |
| 249 | */ |
| 250 | retval = ext2fs_get_num_dirs(fs, &icount->size); |
| 251 | if (retval) |
| 252 | goto errout; |
| 253 | icount->size += fs->super->s_inodes_count / 50; |
| 254 | } |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 255 | |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 256 | bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el)); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 257 | #if 0 |
Eric Sandeen | d0ff90d | 2006-09-12 14:56:15 -0400 | [diff] [blame] | 258 | printf("Icount allocated %u entries, %d bytes.\n", |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 259 | icount->size, bytes); |
| 260 | #endif |
Theodore Ts'o | ee01079 | 2007-11-09 19:01:06 -0500 | [diff] [blame] | 261 | retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el), |
| 262 | &icount->list); |
Theodore Ts'o | 7b4e453 | 1997-10-26 03:41:24 +0000 | [diff] [blame] | 263 | if (retval) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 264 | goto errout; |
| 265 | memset(icount->list, 0, bytes); |
| 266 | |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 267 | icount->count = 0; |
| 268 | icount->cursor = 0; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 269 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 270 | /* |
| 271 | * Populate the sorted list with those entries which were |
| 272 | * found in the hint icount (since those are ones which will |
| 273 | * likely need to be in the sorted list this time around). |
| 274 | */ |
| 275 | if (hint) { |
| 276 | for (i=0; i < hint->count; i++) |
| 277 | icount->list[i].ino = hint->list[i].ino; |
| 278 | icount->count = hint->count; |
| 279 | } |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 280 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 281 | *ret = icount; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 282 | return 0; |
| 283 | |
| 284 | errout: |
| 285 | ext2fs_free_icount(icount); |
| 286 | return(retval); |
| 287 | } |
| 288 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 289 | errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 290 | unsigned int size, |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 291 | ext2_icount_t *ret) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 292 | { |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 293 | return ext2fs_create_icount2(fs, flags, size, 0, ret); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | /* |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 297 | * insert_icount_el() --- Insert a new entry into the sorted list at a |
| 298 | * specified position. |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 299 | */ |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 300 | static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount, |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 301 | ext2_ino_t ino, int pos) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 302 | { |
Theodore Ts'o | 7b4e453 | 1997-10-26 03:41:24 +0000 | [diff] [blame] | 303 | struct ext2_icount_el *el; |
| 304 | errcode_t retval; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 305 | ext2_ino_t new_size = 0; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 306 | int num; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 307 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 308 | if (icount->last_lookup && icount->last_lookup->ino == ino) |
| 309 | return icount->last_lookup; |
| 310 | |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 311 | if (icount->count >= icount->size) { |
| 312 | if (icount->count) { |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 313 | new_size = icount->list[(unsigned)icount->count-1].ino; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 314 | new_size = (ext2_ino_t) (icount->count * |
Theodore Ts'o | 30e50b7 | 2001-06-08 09:43:40 +0000 | [diff] [blame] | 315 | ((float) icount->num_inodes / new_size)); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 316 | } |
| 317 | if (new_size < (icount->size + 100)) |
| 318 | new_size = icount->size + 100; |
| 319 | #if 0 |
Eric Sandeen | d0ff90d | 2006-09-12 14:56:15 -0400 | [diff] [blame] | 320 | printf("Reallocating icount %u entries...\n", new_size); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 321 | #endif |
Theodore Ts'o | 76f875d | 1998-04-27 01:41:13 +0000 | [diff] [blame] | 322 | retval = ext2fs_resize_mem((size_t) icount->size * |
| 323 | sizeof(struct ext2_icount_el), |
| 324 | (size_t) new_size * |
Theodore Ts'o | 7b4e453 | 1997-10-26 03:41:24 +0000 | [diff] [blame] | 325 | sizeof(struct ext2_icount_el), |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 326 | &icount->list); |
Theodore Ts'o | 7b4e453 | 1997-10-26 03:41:24 +0000 | [diff] [blame] | 327 | if (retval) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 328 | return 0; |
| 329 | icount->size = new_size; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 330 | } |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 331 | num = (int) icount->count - pos; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 332 | if (num < 0) |
| 333 | return 0; /* should never happen */ |
| 334 | if (num) { |
| 335 | memmove(&icount->list[pos+1], &icount->list[pos], |
| 336 | sizeof(struct ext2_icount_el) * num); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 337 | } |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 338 | icount->count++; |
| 339 | el = &icount->list[pos]; |
| 340 | el->count = 0; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 341 | el->ino = ino; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 342 | icount->last_lookup = el; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 343 | return el; |
| 344 | } |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 345 | |
| 346 | /* |
| 347 | * get_icount_el() --- given an inode number, try to find icount |
| 348 | * information in the sorted list. If the create flag is set, |
| 349 | * and we can't find an entry, create one in the sorted list. |
| 350 | */ |
| 351 | static struct ext2_icount_el *get_icount_el(ext2_icount_t icount, |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 352 | ext2_ino_t ino, int create) |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 353 | { |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 354 | int low, high, mid; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 355 | |
| 356 | if (!icount || !icount->list) |
| 357 | return 0; |
| 358 | |
| 359 | if (create && ((icount->count == 0) || |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 360 | (ino > icount->list[(unsigned)icount->count-1].ino))) { |
| 361 | return insert_icount_el(icount, ino, (unsigned) icount->count); |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 362 | } |
| 363 | if (icount->count == 0) |
| 364 | return 0; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 365 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 366 | if (icount->cursor >= icount->count) |
| 367 | icount->cursor = 0; |
| 368 | if (ino == icount->list[icount->cursor].ino) |
| 369 | return &icount->list[icount->cursor++]; |
| 370 | #if 0 |
| 371 | printf("Non-cursor get_icount_el: %u\n", ino); |
| 372 | #endif |
| 373 | low = 0; |
Theodore Ts'o | 3cb6c50 | 1997-08-11 20:29:22 +0000 | [diff] [blame] | 374 | high = (int) icount->count-1; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 375 | while (low <= high) { |
Theodore Ts'o | a4aff9c | 2011-08-31 14:27:21 -0400 | [diff] [blame] | 376 | mid = ((unsigned)low + (unsigned)high) >> 1; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 377 | if (ino == icount->list[mid].ino) { |
| 378 | icount->cursor = mid+1; |
| 379 | return &icount->list[mid]; |
| 380 | } |
| 381 | if (ino < icount->list[mid].ino) |
| 382 | high = mid-1; |
| 383 | else |
| 384 | low = mid+1; |
| 385 | } |
| 386 | /* |
| 387 | * If we need to create a new entry, it should be right at |
| 388 | * low (where high will be left at low-1). |
| 389 | */ |
| 390 | if (create) |
| 391 | return insert_icount_el(icount, ino, low); |
| 392 | return 0; |
| 393 | } |
| 394 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 395 | static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino, |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 396 | __u32 count) |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 397 | { |
| 398 | struct ext2_icount_el *el; |
| 399 | TDB_DATA key, data; |
| 400 | |
| 401 | if (icount->tdb) { |
| 402 | key.dptr = (unsigned char *) &ino; |
| 403 | key.dsize = sizeof(ext2_ino_t); |
| 404 | data.dptr = (unsigned char *) &count; |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 405 | data.dsize = sizeof(__u32); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 406 | if (count) { |
| 407 | if (tdb_store(icount->tdb, key, data, TDB_REPLACE)) |
| 408 | return tdb_error(icount->tdb) + |
| 409 | EXT2_ET_TDB_SUCCESS; |
| 410 | } else { |
| 411 | if (tdb_delete(icount->tdb, key)) |
| 412 | return tdb_error(icount->tdb) + |
| 413 | EXT2_ET_TDB_SUCCESS; |
| 414 | } |
| 415 | return 0; |
| 416 | } |
| 417 | |
| 418 | el = get_icount_el(icount, ino, 1); |
| 419 | if (!el) |
| 420 | return EXT2_ET_NO_MEMORY; |
| 421 | |
| 422 | el->count = count; |
| 423 | return 0; |
| 424 | } |
| 425 | |
| 426 | static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino, |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 427 | __u32 *count) |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 428 | { |
| 429 | struct ext2_icount_el *el; |
| 430 | TDB_DATA key, data; |
| 431 | |
| 432 | if (icount->tdb) { |
| 433 | key.dptr = (unsigned char *) &ino; |
| 434 | key.dsize = sizeof(ext2_ino_t); |
| 435 | |
| 436 | data = tdb_fetch(icount->tdb, key); |
| 437 | if (data.dptr == NULL) { |
| 438 | *count = 0; |
| 439 | return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS; |
| 440 | } |
| 441 | |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 442 | *count = *((__u32 *) data.dptr); |
Theodore Ts'o | a1f6427 | 2007-04-06 23:28:30 -0400 | [diff] [blame] | 443 | free(data.dptr); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 444 | return 0; |
| 445 | } |
| 446 | el = get_icount_el(icount, ino, 0); |
| 447 | if (!el) { |
| 448 | *count = 0; |
| 449 | return ENOENT; |
| 450 | } |
| 451 | |
| 452 | *count = el->count; |
| 453 | return 0; |
| 454 | } |
| 455 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 456 | errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out) |
| 457 | { |
| 458 | errcode_t ret = 0; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 459 | unsigned int i; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 460 | const char *bad = "bad icount"; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 461 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 462 | EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); |
| 463 | |
| 464 | if (icount->count > icount->size) { |
| 465 | fprintf(out, "%s: count > size\n", bad); |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 466 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 467 | } |
| 468 | for (i=1; i < icount->count; i++) { |
| 469 | if (icount->list[i-1].ino >= icount->list[i].ino) { |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 470 | fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n", |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 471 | bad, i-1, icount->list[i-1].ino, |
| 472 | i, icount->list[i].ino); |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 473 | ret = EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 474 | } |
| 475 | } |
| 476 | return ret; |
| 477 | } |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 478 | |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 479 | errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 480 | { |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 481 | __u32 val; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 482 | EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); |
| 483 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 484 | if (!ino || (ino > icount->num_inodes)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 485 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 486 | |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 487 | if (ext2fs_test_inode_bitmap2(icount->single, ino)) { |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 488 | *ret = 1; |
| 489 | return 0; |
| 490 | } |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 491 | if (icount->multiple && |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 492 | !ext2fs_test_inode_bitmap2(icount->multiple, ino)) { |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 493 | *ret = 0; |
| 494 | return 0; |
| 495 | } |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 496 | get_inode_count(icount, ino, &val); |
| 497 | *ret = icount_16_xlate(val); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 498 | return 0; |
| 499 | } |
| 500 | |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 501 | errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 502 | __u16 *ret) |
| 503 | { |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 504 | __u32 curr_value; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 505 | |
| 506 | EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); |
| 507 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 508 | if (!ino || (ino > icount->num_inodes)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 509 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 510 | |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 511 | if (ext2fs_test_inode_bitmap2(icount->single, ino)) { |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 512 | /* |
| 513 | * If the existing count is 1, then we know there is |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 514 | * no entry in the list. |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 515 | */ |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 516 | if (set_inode_count(icount, ino, 2)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 517 | return EXT2_ET_NO_MEMORY; |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 518 | curr_value = 2; |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 519 | ext2fs_unmark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 520 | } else if (icount->multiple) { |
| 521 | /* |
| 522 | * The count is either zero or greater than 1; if the |
| 523 | * inode is set in icount->multiple, then there should |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 524 | * be an entry in the list, so we need to fix it. |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 525 | */ |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 526 | if (ext2fs_test_inode_bitmap2(icount->multiple, ino)) { |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 527 | get_inode_count(icount, ino, &curr_value); |
| 528 | curr_value++; |
| 529 | if (set_inode_count(icount, ino, curr_value)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 530 | return EXT2_ET_NO_MEMORY; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 531 | } else { |
| 532 | /* |
| 533 | * The count was zero; mark the single bitmap |
| 534 | * and return. |
| 535 | */ |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 536 | ext2fs_mark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 537 | if (ret) |
| 538 | *ret = 1; |
| 539 | return 0; |
| 540 | } |
| 541 | } else { |
| 542 | /* |
| 543 | * The count is either zero or greater than 1; try to |
| 544 | * find an entry in the list to determine which. |
| 545 | */ |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 546 | get_inode_count(icount, ino, &curr_value); |
| 547 | curr_value++; |
| 548 | if (set_inode_count(icount, ino, curr_value)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 549 | return EXT2_ET_NO_MEMORY; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 550 | } |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 551 | if (icount->multiple) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 552 | ext2fs_mark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 553 | if (ret) |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 554 | *ret = icount_16_xlate(curr_value); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 555 | return 0; |
| 556 | } |
| 557 | |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 558 | errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 559 | __u16 *ret) |
| 560 | { |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 561 | __u32 curr_value; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 562 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 563 | if (!ino || (ino > icount->num_inodes)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 564 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 565 | |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 566 | EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); |
| 567 | |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 568 | if (ext2fs_test_inode_bitmap2(icount->single, ino)) { |
| 569 | ext2fs_unmark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 570 | if (icount->multiple) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 571 | ext2fs_unmark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 572 | else { |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 573 | set_inode_count(icount, ino, 0); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 574 | } |
| 575 | if (ret) |
| 576 | *ret = 0; |
| 577 | return 0; |
| 578 | } |
| 579 | |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 580 | if (icount->multiple && |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 581 | !ext2fs_test_inode_bitmap2(icount->multiple, ino)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 582 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 583 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 584 | get_inode_count(icount, ino, &curr_value); |
| 585 | if (!curr_value) |
| 586 | return EXT2_ET_INVALID_ARGUMENT; |
| 587 | curr_value--; |
| 588 | if (set_inode_count(icount, ino, curr_value)) |
| 589 | return EXT2_ET_NO_MEMORY; |
| 590 | |
| 591 | if (curr_value == 1) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 592 | ext2fs_mark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 593 | if ((curr_value == 0) && icount->multiple) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 594 | ext2fs_unmark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 595 | |
| 596 | if (ret) |
Theodore Ts'o | 60bbd1a | 2008-03-13 13:37:29 -0400 | [diff] [blame] | 597 | *ret = icount_16_xlate(curr_value); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 598 | return 0; |
| 599 | } |
| 600 | |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 601 | errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 602 | __u16 count) |
| 603 | { |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 604 | if (!ino || (ino > icount->num_inodes)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 605 | return EXT2_ET_INVALID_ARGUMENT; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 606 | |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 607 | EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); |
| 608 | |
| 609 | if (count == 1) { |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 610 | ext2fs_mark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 611 | if (icount->multiple) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 612 | ext2fs_unmark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 613 | return 0; |
| 614 | } |
| 615 | if (count == 0) { |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 616 | ext2fs_unmark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 617 | if (icount->multiple) { |
| 618 | /* |
| 619 | * If the icount->multiple bitmap is enabled, |
| 620 | * we can just clear both bitmaps and we're done |
| 621 | */ |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 622 | ext2fs_unmark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 623 | } else |
| 624 | set_inode_count(icount, ino, 0); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 625 | return 0; |
| 626 | } |
| 627 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 628 | if (set_inode_count(icount, ino, count)) |
Theodore Ts'o | 1f0b6c1 | 1997-10-31 06:07:47 +0000 | [diff] [blame] | 629 | return EXT2_ET_NO_MEMORY; |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 630 | ext2fs_unmark_inode_bitmap2(icount->single, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 631 | if (icount->multiple) |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 632 | ext2fs_mark_inode_bitmap2(icount->multiple, ino); |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 633 | return 0; |
| 634 | } |
| 635 | |
Theodore Ts'o | 31dbecd | 2001-01-11 04:54:39 +0000 | [diff] [blame] | 636 | ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount) |
Theodore Ts'o | 19c78dc | 1997-04-29 16:17:09 +0000 | [diff] [blame] | 637 | { |
| 638 | if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT) |
| 639 | return 0; |
| 640 | |
| 641 | return icount->size; |
| 642 | } |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 643 | |
| 644 | #ifdef DEBUG |
| 645 | |
| 646 | ext2_filsys test_fs; |
| 647 | ext2_icount_t icount; |
| 648 | |
| 649 | #define EXIT 0x00 |
| 650 | #define FETCH 0x01 |
| 651 | #define STORE 0x02 |
| 652 | #define INCREMENT 0x03 |
| 653 | #define DECREMENT 0x04 |
| 654 | |
| 655 | struct test_program { |
| 656 | int cmd; |
| 657 | ext2_ino_t ino; |
| 658 | __u16 arg; |
| 659 | __u16 expected; |
| 660 | }; |
| 661 | |
| 662 | struct test_program prog[] = { |
| 663 | { STORE, 42, 42, 42 }, |
| 664 | { STORE, 1, 1, 1 }, |
| 665 | { STORE, 2, 2, 2 }, |
| 666 | { STORE, 3, 3, 3 }, |
| 667 | { STORE, 10, 1, 1 }, |
| 668 | { STORE, 42, 0, 0 }, |
| 669 | { INCREMENT, 5, 0, 1 }, |
| 670 | { INCREMENT, 5, 0, 2 }, |
| 671 | { INCREMENT, 5, 0, 3 }, |
| 672 | { INCREMENT, 5, 0, 4 }, |
| 673 | { DECREMENT, 5, 0, 3 }, |
| 674 | { DECREMENT, 5, 0, 2 }, |
| 675 | { DECREMENT, 5, 0, 1 }, |
| 676 | { DECREMENT, 5, 0, 0 }, |
| 677 | { FETCH, 10, 0, 1 }, |
| 678 | { FETCH, 1, 0, 1 }, |
| 679 | { FETCH, 2, 0, 2 }, |
| 680 | { FETCH, 3, 0, 3 }, |
| 681 | { INCREMENT, 1, 0, 2 }, |
| 682 | { DECREMENT, 2, 0, 1 }, |
| 683 | { DECREMENT, 2, 0, 0 }, |
| 684 | { FETCH, 12, 0, 0 }, |
| 685 | { EXIT, 0, 0, 0 } |
| 686 | }; |
| 687 | |
| 688 | struct test_program extended[] = { |
| 689 | { STORE, 1, 1, 1 }, |
| 690 | { STORE, 2, 2, 2 }, |
| 691 | { STORE, 3, 3, 3 }, |
| 692 | { STORE, 4, 4, 4 }, |
| 693 | { STORE, 5, 5, 5 }, |
| 694 | { STORE, 6, 1, 1 }, |
| 695 | { STORE, 7, 2, 2 }, |
| 696 | { STORE, 8, 3, 3 }, |
| 697 | { STORE, 9, 4, 4 }, |
| 698 | { STORE, 10, 5, 5 }, |
| 699 | { STORE, 11, 1, 1 }, |
| 700 | { STORE, 12, 2, 2 }, |
| 701 | { STORE, 13, 3, 3 }, |
| 702 | { STORE, 14, 4, 4 }, |
| 703 | { STORE, 15, 5, 5 }, |
| 704 | { STORE, 16, 1, 1 }, |
| 705 | { STORE, 17, 2, 2 }, |
| 706 | { STORE, 18, 3, 3 }, |
| 707 | { STORE, 19, 4, 4 }, |
| 708 | { STORE, 20, 5, 5 }, |
| 709 | { STORE, 21, 1, 1 }, |
| 710 | { STORE, 22, 2, 2 }, |
| 711 | { STORE, 23, 3, 3 }, |
| 712 | { STORE, 24, 4, 4 }, |
| 713 | { STORE, 25, 5, 5 }, |
| 714 | { STORE, 26, 1, 1 }, |
| 715 | { STORE, 27, 2, 2 }, |
| 716 | { STORE, 28, 3, 3 }, |
| 717 | { STORE, 29, 4, 4 }, |
| 718 | { STORE, 30, 5, 5 }, |
| 719 | { EXIT, 0, 0, 0 } |
| 720 | }; |
| 721 | |
| 722 | /* |
| 723 | * Setup the variables for doing the inode scan test. |
| 724 | */ |
| 725 | static void setup(void) |
| 726 | { |
| 727 | errcode_t retval; |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 728 | struct ext2_super_block param; |
| 729 | |
| 730 | initialize_ext2_error_table(); |
| 731 | |
| 732 | memset(¶m, 0, sizeof(param)); |
Valerie Aurora Henson | 4efbac6 | 2009-09-07 20:46:34 -0400 | [diff] [blame] | 733 | ext2fs_blocks_count_set(¶m, 12000); |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 734 | |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 735 | retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 736 | test_io_manager, &test_fs); |
| 737 | if (retval) { |
| 738 | com_err("setup", retval, |
| 739 | "while initializing filesystem"); |
| 740 | exit(1); |
| 741 | } |
| 742 | retval = ext2fs_allocate_tables(test_fs); |
| 743 | if (retval) { |
| 744 | com_err("setup", retval, |
| 745 | "while allocating tables for test filesystem"); |
| 746 | exit(1); |
| 747 | } |
| 748 | } |
| 749 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 750 | int run_test(int flags, int size, char *dir, struct test_program *prog) |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 751 | { |
| 752 | errcode_t retval; |
| 753 | ext2_icount_t icount; |
| 754 | struct test_program *pc; |
| 755 | __u16 result; |
| 756 | int problem = 0; |
| 757 | |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 758 | if (dir) { |
| 759 | retval = ext2fs_create_icount_tdb(test_fs, dir, |
| 760 | flags, &icount); |
| 761 | if (retval) { |
| 762 | com_err("run_test", retval, |
| 763 | "while creating icount using tdb"); |
| 764 | exit(1); |
| 765 | } |
| 766 | } else { |
| 767 | retval = ext2fs_create_icount2(test_fs, flags, size, 0, |
| 768 | &icount); |
| 769 | if (retval) { |
| 770 | com_err("run_test", retval, "while creating icount"); |
| 771 | exit(1); |
| 772 | } |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 773 | } |
| 774 | for (pc = prog; pc->cmd != EXIT; pc++) { |
| 775 | switch (pc->cmd) { |
| 776 | case FETCH: |
| 777 | printf("icount_fetch(%u) = ", pc->ino); |
| 778 | break; |
| 779 | case STORE: |
| 780 | retval = ext2fs_icount_store(icount, pc->ino, pc->arg); |
| 781 | if (retval) { |
| 782 | com_err("run_test", retval, |
| 783 | "while calling icount_store"); |
| 784 | exit(1); |
| 785 | } |
| 786 | printf("icount_store(%u, %u) = ", pc->ino, pc->arg); |
| 787 | break; |
| 788 | case INCREMENT: |
| 789 | retval = ext2fs_icount_increment(icount, pc->ino, 0); |
| 790 | if (retval) { |
| 791 | com_err("run_test", retval, |
| 792 | "while calling icount_increment"); |
| 793 | exit(1); |
| 794 | } |
| 795 | printf("icount_increment(%u) = ", pc->ino); |
| 796 | break; |
| 797 | case DECREMENT: |
| 798 | retval = ext2fs_icount_decrement(icount, pc->ino, 0); |
| 799 | if (retval) { |
| 800 | com_err("run_test", retval, |
| 801 | "while calling icount_decrement"); |
| 802 | exit(1); |
| 803 | } |
| 804 | printf("icount_decrement(%u) = ", pc->ino); |
| 805 | break; |
| 806 | } |
| 807 | retval = ext2fs_icount_fetch(icount, pc->ino, &result); |
| 808 | if (retval) { |
| 809 | com_err("run_test", retval, |
| 810 | "while calling icount_fetch"); |
| 811 | exit(1); |
| 812 | } |
| 813 | printf("%u (%s)\n", result, (result == pc->expected) ? |
| 814 | "OK" : "NOT OK"); |
| 815 | if (result != pc->expected) |
| 816 | problem++; |
| 817 | } |
| 818 | printf("icount size is %u\n", ext2fs_get_icount_size(icount)); |
| 819 | retval = ext2fs_icount_validate(icount, stdout); |
| 820 | if (retval) { |
| 821 | com_err("run_test", retval, "while calling icount_validate"); |
| 822 | exit(1); |
| 823 | } |
| 824 | ext2fs_free_icount(icount); |
| 825 | return problem; |
| 826 | } |
| 827 | |
| 828 | |
| 829 | int main(int argc, char **argv) |
| 830 | { |
| 831 | int failed = 0; |
| 832 | |
| 833 | setup(); |
| 834 | printf("Standard icount run:\n"); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 835 | failed += run_test(0, 0, 0, prog); |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 836 | printf("\nMultiple bitmap test:\n"); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 837 | failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog); |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 838 | printf("\nResizing icount:\n"); |
Theodore Ts'o | 1b9d8cb | 2007-04-06 14:30:39 -0400 | [diff] [blame] | 839 | failed += run_test(0, 3, 0, extended); |
| 840 | printf("\nStandard icount run with tdb:\n"); |
| 841 | failed += run_test(0, 0, ".", prog); |
| 842 | printf("\nMultiple bitmap test with tdb:\n"); |
| 843 | failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog); |
| 844 | if (failed) |
Theodore Ts'o | 1cb78d8 | 2007-04-06 08:52:49 -0400 | [diff] [blame] | 845 | printf("FAILED!\n"); |
| 846 | return failed; |
| 847 | } |
| 848 | #endif |