Blame view
fs/gfs2/dir.c
47.3 KB
b3b94faa5 [GFS2] The core o... |
1 2 |
/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
3a8a9a103 [GFS2] Update cop... |
3 |
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
b3b94faa5 [GFS2] The core o... |
4 5 6 |
* * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions |
e9fc2aa09 [GFS2] Update cop... |
7 |
* of the GNU General Public License version 2. |
b3b94faa5 [GFS2] The core o... |
8 9 10 |
*/ /* |
61e085a88 [GFS2] Tidy up di... |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
* Implements Extendible Hashing as described in: * "Extendible Hashing" by Fagin, et al in * __ACM Trans. on Database Systems__, Sept 1979. * * * Here's the layout of dirents which is essentially the same as that of ext2 * within a single block. The field de_name_len is the number of bytes * actually required for the name (no null terminator). The field de_rec_len * is the number of bytes allocated to the dirent. The offset of the next * dirent in the block is (dirent + dirent->de_rec_len). When a dirent is * deleted, the preceding dirent inherits its allocated space, ie * prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained * by adding de_rec_len to the current dirent, this essentially causes the * deleted dirent to get jumped over when iterating through all the dirents. * * When deleting the first dirent in a block, there is no previous dirent so * the field de_ino is set to zero to designate it as deleted. When allocating * a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the * first dirent has (de_ino == 0) and de_rec_len is large enough, this first * dirent is allocated. Otherwise it must go through all the 'used' dirents * searching for one in which the amount of total space minus the amount of * used space will provide enough space for the new dirent. * * There are two types of blocks in which dirents reside. In a stuffed dinode, * the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of * the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the * beginning of the leaf block. The dirents reside in leaves when * |
383f01fbf GFS2: Banish stru... |
39 |
* dip->i_diskflags & GFS2_DIF_EXHASH is true |
61e085a88 [GFS2] Tidy up di... |
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
* * Otherwise, the dirents are "linear", within a single stuffed dinode block. * * When the dirents are in leaves, the actual contents of the directory file are * used as an array of 64-bit block pointers pointing to the leaf blocks. The * dirents are NOT in the directory file itself. There can be more than one * block pointer in the array that points to the same leaf. In fact, when a * directory is first converted from linear to exhash, all of the pointers * point to the same leaf. * * When a leaf is completely full, the size of the hash table can be * doubled unless it is already at the maximum size which is hard coded into * GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list, * but never before the maximum hash table size has been reached. */ |
b3b94faa5 [GFS2] The core o... |
55 |
|
b3b94faa5 [GFS2] The core o... |
56 57 |
#include <linux/slab.h> #include <linux/spinlock.h> |
b3b94faa5 [GFS2] The core o... |
58 59 |
#include <linux/buffer_head.h> #include <linux/sort.h> |
5c676f6d3 [GFS2] Macros rem... |
60 |
#include <linux/gfs2_ondisk.h> |
71b86f562 [GFS2] Further up... |
61 |
#include <linux/crc32.h> |
fe1bdedc6 [GFS2] Use vmallo... |
62 |
#include <linux/vmalloc.h> |
b3b94faa5 [GFS2] The core o... |
63 64 |
#include "gfs2.h" |
5c676f6d3 [GFS2] Macros rem... |
65 |
#include "incore.h" |
b3b94faa5 [GFS2] The core o... |
66 67 68 |
#include "dir.h" #include "glock.h" #include "inode.h" |
b3b94faa5 [GFS2] The core o... |
69 70 71 72 |
#include "meta_io.h" #include "quota.h" #include "rgrp.h" #include "trans.h" |
e13940ba5 [GFS2] Make dir.c... |
73 |
#include "bmap.h" |
5c676f6d3 [GFS2] Macros rem... |
74 |
#include "util.h" |
b3b94faa5 [GFS2] The core o... |
75 76 77 |
#define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ |
dfe4d34b3 GFS2: Add readahe... |
78 |
#define MAX_RA_BLOCKS 32 /* max read-ahead blocks */ |
cd915493f [GFS2] Change all... |
79 80 |
#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) |
b3b94faa5 [GFS2] The core o... |
81 |
|
8d1235852 GFS2: Make . and ... |
82 83 |
struct qstr gfs2_qdot __read_mostly; struct qstr gfs2_qdotdot __read_mostly; |
2bdbc5d73 [GFS2] Directory ... |
84 85 |
typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); |
b3b94faa5 [GFS2] The core o... |
86 |
|
cd915493f [GFS2] Change all... |
87 |
int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, |
61e085a88 [GFS2] Tidy up di... |
88 |
struct buffer_head **bhp) |
e13940ba5 [GFS2] Make dir.c... |
89 90 |
{ struct buffer_head *bh; |
e13940ba5 [GFS2] Make dir.c... |
91 |
|
61e085a88 [GFS2] Tidy up di... |
92 93 94 95 |
bh = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); |
e13940ba5 [GFS2] Make dir.c... |
96 97 98 |
*bhp = bh; return 0; } |
cd915493f [GFS2] Change all... |
99 |
static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, |
61e085a88 [GFS2] Tidy up di... |
100 101 102 103 |
struct buffer_head **bhp) { struct buffer_head *bh; int error; |
e13940ba5 [GFS2] Make dir.c... |
104 |
|
7276b3b0c [GFS2] Tidy up me... |
105 |
error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); |
61e085a88 [GFS2] Tidy up di... |
106 107 |
if (error) return error; |
feaa7bba0 [GFS2] Fix unlink... |
108 |
if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { |
61e085a88 [GFS2] Tidy up di... |
109 110 111 112 113 114 |
brelse(bh); return -EIO; } *bhp = bh; return 0; } |
e13940ba5 [GFS2] Make dir.c... |
115 116 117 |
static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, unsigned int offset, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
118 119 120 121 122 123 124 125 126 |
{ struct buffer_head *dibh; int error; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
c752666c1 [GFS2] Fix bug in... |
127 |
memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); |
a2e0f7993 GFS2: Remove i_di... |
128 129 |
if (ip->i_inode.i_size < offset + size) i_size_write(&ip->i_inode, offset + size); |
4bd91ba18 [GFS2] Add nanose... |
130 |
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
539e5d6b7 [GFS2] Change arg... |
131 |
gfs2_dinode_out(ip, dibh->b_data); |
e13940ba5 [GFS2] Make dir.c... |
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
brelse(dibh); return size; } /** * gfs2_dir_write_data - Write directory information to the inode * @ip: The GFS2 inode * @buf: The buffer containing information to be written * @offset: The file offset to start writing at * @size: The amount of data to write * * Returns: The number of bytes correctly written or error code */ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, |
cd915493f [GFS2] Change all... |
150 |
u64 offset, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
151 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
152 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
e13940ba5 [GFS2] Make dir.c... |
153 |
struct buffer_head *dibh; |
cd915493f [GFS2] Change all... |
154 155 |
u64 lblock, dblock; u32 extlen = 0; |
e13940ba5 [GFS2] Make dir.c... |
156 157 158 |
unsigned int o; int copied = 0; int error = 0; |
9b8c81d1d [GFS2] Allow bmap... |
159 |
int new = 0; |
e13940ba5 [GFS2] Make dir.c... |
160 161 162 163 164 165 |
if (!size) return 0; if (gfs2_is_stuffed(ip) && offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) |
568f4c965 [GFS2] 80 Column ... |
166 167 |
return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset, size); |
e13940ba5 [GFS2] Make dir.c... |
168 169 170 171 172 |
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; if (gfs2_is_stuffed(ip)) { |
f25ef0c1b [GFS2] Tidy gfs2_... |
173 |
error = gfs2_unstuff_dinode(ip, NULL); |
e13940ba5 [GFS2] Make dir.c... |
174 |
if (error) |
c752666c1 [GFS2] Fix bug in... |
175 |
return error; |
e13940ba5 [GFS2] Make dir.c... |
176 177 178 179 180 181 182 183 |
} lblock = offset; o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); while (copied < size) { unsigned int amount; struct buffer_head *bh; |
e13940ba5 [GFS2] Make dir.c... |
184 185 186 187 188 189 190 |
amount = size - copied; if (amount > sdp->sd_sb.sb_bsize - o) amount = sdp->sd_sb.sb_bsize - o; if (!extlen) { new = 1; |
feaa7bba0 [GFS2] Fix unlink... |
191 |
error = gfs2_extent_map(&ip->i_inode, lblock, &new, |
fd88de569 [GFS2] Readpages ... |
192 |
&dblock, &extlen); |
e13940ba5 [GFS2] Make dir.c... |
193 194 195 196 197 198 |
if (error) goto fail; error = -EIO; if (gfs2_assert_withdraw(sdp, dblock)) goto fail; } |
61e085a88 [GFS2] Tidy up di... |
199 200 201 202 |
if (amount == sdp->sd_jbsize || new) error = gfs2_dir_get_new_buffer(ip, dblock, &bh); else error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); |
e13940ba5 [GFS2] Make dir.c... |
203 204 205 206 207 208 |
if (error) goto fail; gfs2_trans_add_bh(ip->i_gl, bh, 1); memcpy(bh->b_data + o, buf, amount); brelse(bh); |
e13940ba5 [GFS2] Make dir.c... |
209 |
|
899bb2645 [GFS2] Fix bug in... |
210 |
buf += amount; |
e13940ba5 [GFS2] Make dir.c... |
211 212 213 214 215 216 217 218 219 220 221 222 |
copied += amount; lblock++; dblock++; extlen--; o = sizeof(struct gfs2_meta_header); } out: error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; |
a2e0f7993 GFS2: Remove i_di... |
223 224 |
if (ip->i_inode.i_size < offset + copied) i_size_write(&ip->i_inode, offset + copied); |
4bd91ba18 [GFS2] Add nanose... |
225 |
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
e13940ba5 [GFS2] Make dir.c... |
226 227 |
gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
539e5d6b7 [GFS2] Change arg... |
228 |
gfs2_dinode_out(ip, dibh->b_data); |
e13940ba5 [GFS2] Make dir.c... |
229 230 231 232 233 234 235 236 |
brelse(dibh); return copied; fail: if (copied) goto out; return error; } |
4c28d3380 GFS2: Clean up di... |
237 238 |
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
239 240 241 242 243 244 |
{ struct buffer_head *dibh; int error; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { |
4c28d3380 GFS2: Clean up di... |
245 |
memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size); |
e13940ba5 [GFS2] Make dir.c... |
246 247 248 249 250 251 252 253 254 255 256 |
brelse(dibh); } return (error) ? error : size; } /** * gfs2_dir_read_data - Read a data from a directory inode * @ip: The GFS2 Inode * @buf: The buffer to place result into |
e13940ba5 [GFS2] Make dir.c... |
257 258 259 260 |
* @size: Amount of data to transfer * * Returns: The amount of data actually copied or the error */ |
4c28d3380 GFS2: Clean up di... |
261 262 |
static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
263 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
264 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
cd915493f [GFS2] Change all... |
265 266 |
u64 lblock, dblock; u32 extlen = 0; |
e13940ba5 [GFS2] Make dir.c... |
267 268 269 |
unsigned int o; int copied = 0; int error = 0; |
e13940ba5 [GFS2] Make dir.c... |
270 271 |
if (gfs2_is_stuffed(ip)) |
4c28d3380 GFS2: Clean up di... |
272 |
return gfs2_dir_read_stuffed(ip, buf, size); |
e13940ba5 [GFS2] Make dir.c... |
273 274 275 |
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; |
4c28d3380 GFS2: Clean up di... |
276 |
lblock = 0; |
e13940ba5 [GFS2] Make dir.c... |
277 278 279 280 281 282 283 284 285 286 287 288 289 |
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); while (copied < size) { unsigned int amount; struct buffer_head *bh; int new; amount = size - copied; if (amount > sdp->sd_sb.sb_bsize - o) amount = sdp->sd_sb.sb_bsize - o; if (!extlen) { new = 0; |
feaa7bba0 [GFS2] Fix unlink... |
290 |
error = gfs2_extent_map(&ip->i_inode, lblock, &new, |
fd88de569 [GFS2] Readpages ... |
291 |
&dblock, &extlen); |
7276b3b0c [GFS2] Tidy up me... |
292 |
if (error || !dblock) |
e13940ba5 [GFS2] Make dir.c... |
293 |
goto fail; |
7276b3b0c [GFS2] Tidy up me... |
294 |
BUG_ON(extlen < 1); |
7276b3b0c [GFS2] Tidy up me... |
295 |
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); |
b7d8ac3e1 [GFS2] gfs2_dir_r... |
296 |
} else { |
7276b3b0c [GFS2] Tidy up me... |
297 |
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); |
e13940ba5 [GFS2] Make dir.c... |
298 299 |
if (error) goto fail; |
7276b3b0c [GFS2] Tidy up me... |
300 301 302 303 304 305 306 307 |
} error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD); if (error) { brelse(bh); goto fail; } dblock++; extlen--; |
e13940ba5 [GFS2] Make dir.c... |
308 309 |
memcpy(buf, bh->b_data + o, amount); brelse(bh); |
4c28d3380 GFS2: Clean up di... |
310 |
buf += (amount/sizeof(__be64)); |
e13940ba5 [GFS2] Make dir.c... |
311 312 |
copied += amount; lblock++; |
e13940ba5 [GFS2] Make dir.c... |
313 314 315 316 317 318 319 |
o = sizeof(struct gfs2_meta_header); } return copied; fail: return (copied) ? copied : error; } |
17d539f04 GFS2: Cache dir h... |
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
/** * gfs2_dir_get_hash_table - Get pointer to the dir hash table * @ip: The inode in question * * Returns: The hash table or an error */ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; int ret; u32 hsize; __be64 *hc; BUG_ON(!(ip->i_diskflags & GFS2_DIF_EXHASH)); hc = ip->i_hash_cache; if (hc) return hc; hsize = 1 << ip->i_depth; hsize *= sizeof(__be64); if (hsize != i_size_read(&ip->i_inode)) { gfs2_consist_inode(ip); return ERR_PTR(-EIO); } hc = kmalloc(hsize, GFP_NOFS); ret = -ENOMEM; if (hc == NULL) return ERR_PTR(-ENOMEM); |
4c28d3380 GFS2: Clean up di... |
351 |
ret = gfs2_dir_read_data(ip, hc, hsize); |
17d539f04 GFS2: Cache dir h... |
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
if (ret < 0) { kfree(hc); return ERR_PTR(ret); } spin_lock(&inode->i_lock); if (ip->i_hash_cache) kfree(hc); else ip->i_hash_cache = hc; spin_unlock(&inode->i_lock); return ip->i_hash_cache; } /** * gfs2_dir_hash_inval - Invalidate dir hash * @ip: The directory inode * * Must be called with an exclusive glock, or during glock invalidation. */ void gfs2_dir_hash_inval(struct gfs2_inode *ip) { __be64 *hc = ip->i_hash_cache; ip->i_hash_cache = NULL; kfree(hc); } |
5e7d65cd9 [GFS2] Make senti... |
379 380 381 382 |
static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent) { return dent->de_inum.no_addr == 0 || dent->de_inum.no_formal_ino == 0; } |
c752666c1 [GFS2] Fix bug in... |
383 384 385 |
static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, const struct qstr *name, int ret) { |
5e7d65cd9 [GFS2] Make senti... |
386 |
if (!gfs2_dirent_sentinel(dent) && |
c752666c1 [GFS2] Fix bug in... |
387 388 |
be32_to_cpu(dent->de_hash) == name->hash && be16_to_cpu(dent->de_name_len) == name->len && |
2bdbc5d73 [GFS2] Directory ... |
389 |
memcmp(dent+1, name->name, name->len) == 0) |
c752666c1 [GFS2] Fix bug in... |
390 391 392 393 394 |
return ret; return 0; } static int gfs2_dirent_find(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
395 396 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
397 398 399 400 401 |
{ return __gfs2_dirent_find(dent, name, 1); } static int gfs2_dirent_prev(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
402 403 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
404 405 406 407 408 409 410 |
{ return __gfs2_dirent_find(dent, name, 2); } /* * name->name holds ptr to start of block. * name->len holds size of block. |
b3b94faa5 [GFS2] The core o... |
411 |
*/ |
c752666c1 [GFS2] Fix bug in... |
412 |
static int gfs2_dirent_last(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
413 414 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
415 416 417 418 419 420 421 |
{ const char *start = name->name; const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); if (name->len == (end - start)) return 1; return 0; } |
b3b94faa5 [GFS2] The core o... |
422 |
|
c752666c1 [GFS2] Fix bug in... |
423 |
static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
424 425 |
const struct qstr *name, void *opaque) |
b3b94faa5 [GFS2] The core o... |
426 |
{ |
c752666c1 [GFS2] Fix bug in... |
427 428 429 |
unsigned required = GFS2_DIRENT_SIZE(name->len); unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); unsigned totlen = be16_to_cpu(dent->de_rec_len); |
5e7d65cd9 [GFS2] Make senti... |
430 |
if (gfs2_dirent_sentinel(dent)) |
728a756b8 GFS2: rename caus... |
431 |
actual = 0; |
c53921248 [GFS2] More style... |
432 |
if (totlen - actual >= required) |
c752666c1 [GFS2] Fix bug in... |
433 434 435 |
return 1; return 0; } |
71b86f562 [GFS2] Further up... |
436 437 438 439 440 441 442 443 444 445 |
struct dirent_gather { const struct gfs2_dirent **pdent; unsigned offset; }; static int gfs2_dirent_gather(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque) { struct dirent_gather *g = opaque; |
5e7d65cd9 [GFS2] Make senti... |
446 |
if (!gfs2_dirent_sentinel(dent)) { |
71b86f562 [GFS2] Further up... |
447 448 449 450 |
g->pdent[g->offset++] = dent; } return 0; } |
c752666c1 [GFS2] Fix bug in... |
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
/* * Other possible things to check: * - Inode located within filesystem size (and on valid block) * - Valid directory entry type * Not sure how heavy-weight we want to make this... could also check * hash is correct for example, but that would take a lot of extra time. * For now the most important thing is to check that the various sizes * are correct. */ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, unsigned int size, unsigned int len, int first) { const char *msg = "gfs2_dirent too small"; if (unlikely(size < sizeof(struct gfs2_dirent))) goto error; msg = "gfs2_dirent misaligned"; if (unlikely(offset & 0x7)) goto error; msg = "gfs2_dirent points beyond end of block"; if (unlikely(offset + size > len)) goto error; msg = "zero inode number"; |
5e7d65cd9 [GFS2] Make senti... |
473 |
if (unlikely(!first && gfs2_dirent_sentinel(dent))) |
c752666c1 [GFS2] Fix bug in... |
474 475 |
goto error; msg = "name length is greater than space in dirent"; |
5e7d65cd9 [GFS2] Make senti... |
476 |
if (!gfs2_dirent_sentinel(dent) && |
c752666c1 [GFS2] Fix bug in... |
477 478 479 480 481 482 483 484 485 |
unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) > size)) goto error; return 0; error: printk(KERN_WARNING "gfs2_check_dirent: %s (%s) ", msg, first ? "first in block" : "not first in block"); return -EIO; |
b3b94faa5 [GFS2] The core o... |
486 |
} |
71b86f562 [GFS2] Further up... |
487 |
static int gfs2_dirent_offset(const void *buf) |
c752666c1 [GFS2] Fix bug in... |
488 |
{ |
71b86f562 [GFS2] Further up... |
489 490 |
const struct gfs2_meta_header *h = buf; int offset; |
c752666c1 [GFS2] Fix bug in... |
491 492 |
BUG_ON(buf == NULL); |
c752666c1 [GFS2] Fix bug in... |
493 |
|
e3167ded1 [GFS] Fix bug in ... |
494 |
switch(be32_to_cpu(h->mh_type)) { |
c752666c1 [GFS2] Fix bug in... |
495 496 497 498 499 500 501 502 503 |
case GFS2_METATYPE_LF: offset = sizeof(struct gfs2_leaf); break; case GFS2_METATYPE_DI: offset = sizeof(struct gfs2_dinode); break; default: goto wrong_type; } |
71b86f562 [GFS2] Further up... |
504 505 506 507 |
return offset; wrong_type: printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u ", |
e3167ded1 [GFS] Fix bug in ... |
508 |
be32_to_cpu(h->mh_type)); |
71b86f562 [GFS2] Further up... |
509 510 |
return -1; } |
2bdbc5d73 [GFS2] Directory ... |
511 |
static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, |
71b86f562 [GFS2] Further up... |
512 513 514 515 516 517 518 519 |
unsigned int len, gfs2_dscan_t scan, const struct qstr *name, void *opaque) { struct gfs2_dirent *dent, *prev; unsigned offset; unsigned size; int ret = 0; |
c752666c1 [GFS2] Fix bug in... |
520 |
|
71b86f562 [GFS2] Further up... |
521 522 523 524 525 |
ret = gfs2_dirent_offset(buf); if (ret < 0) goto consist_inode; offset = ret; |
c752666c1 [GFS2] Fix bug in... |
526 |
prev = NULL; |
2bdbc5d73 [GFS2] Directory ... |
527 |
dent = buf + offset; |
c752666c1 [GFS2] Fix bug in... |
528 529 530 531 |
size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 1)) goto consist_inode; do { |
71b86f562 [GFS2] Further up... |
532 |
ret = scan(dent, name, opaque); |
c752666c1 [GFS2] Fix bug in... |
533 534 535 536 537 538 |
if (ret) break; offset += size; if (offset == len) break; prev = dent; |
2bdbc5d73 [GFS2] Directory ... |
539 |
dent = buf + offset; |
c752666c1 [GFS2] Fix bug in... |
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 |
size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 0)) goto consist_inode; } while(1); switch(ret) { case 0: return NULL; case 1: return dent; case 2: return prev ? prev : dent; default: BUG_ON(ret > 0); return ERR_PTR(ret); } |
c752666c1 [GFS2] Fix bug in... |
556 |
consist_inode: |
feaa7bba0 [GFS2] Fix unlink... |
557 |
gfs2_consist_inode(GFS2_I(inode)); |
c752666c1 [GFS2] Fix bug in... |
558 559 |
return ERR_PTR(-EIO); } |
2bdbc5d73 [GFS2] Directory ... |
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
static int dirent_check_reclen(struct gfs2_inode *dip, const struct gfs2_dirent *d, const void *end_p) { const void *ptr = d; u16 rec_len = be16_to_cpu(d->de_rec_len); if (unlikely(rec_len < sizeof(struct gfs2_dirent))) goto broken; ptr += rec_len; if (ptr < end_p) return rec_len; if (ptr == end_p) return -ENOENT; broken: gfs2_consist_inode(dip); return -EIO; } |
b3b94faa5 [GFS2] The core o... |
577 578 579 580 581 582 583 584 585 586 587 588 |
/** * dirent_next - Next dirent * @dip: the directory * @bh: The buffer * @dent: Pointer to list of dirents * * Returns: 0 on success, error code otherwise */ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent **dent) { |
2bdbc5d73 [GFS2] Directory ... |
589 590 591 |
struct gfs2_dirent *cur = *dent, *tmp; char *bh_end = bh->b_data + bh->b_size; int ret; |
b3b94faa5 [GFS2] The core o... |
592 |
|
2bdbc5d73 [GFS2] Directory ... |
593 594 595 |
ret = dirent_check_reclen(dip, cur, bh_end); if (ret < 0) return ret; |
4dd651adb [GFS2] Fix the bu... |
596 |
|
2bdbc5d73 [GFS2] Directory ... |
597 598 599 600 |
tmp = (void *)cur + ret; ret = dirent_check_reclen(dip, tmp, bh_end); if (ret == -EIO) return ret; |
4dd651adb [GFS2] Fix the bu... |
601 |
|
b3b94faa5 [GFS2] The core o... |
602 |
/* Only the first dent could ever have de_inum.no_addr == 0 */ |
5e7d65cd9 [GFS2] Make senti... |
603 |
if (gfs2_dirent_sentinel(tmp)) { |
b3b94faa5 [GFS2] The core o... |
604 605 606 607 608 |
gfs2_consist_inode(dip); return -EIO; } *dent = tmp; |
b3b94faa5 [GFS2] The core o... |
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
return 0; } /** * dirent_del - Delete a dirent * @dip: The GFS2 inode * @bh: The buffer * @prev: The previous dirent * @cur: The current dirent * */ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent *prev, struct gfs2_dirent *cur) { |
cd915493f [GFS2] Change all... |
624 |
u16 cur_rec_len, prev_rec_len; |
b3b94faa5 [GFS2] The core o... |
625 |
|
5e7d65cd9 [GFS2] Make senti... |
626 |
if (gfs2_dirent_sentinel(cur)) { |
b3b94faa5 [GFS2] The core o... |
627 628 629 |
gfs2_consist_inode(dip); return; } |
d4e9c4c3b [GFS2] Add an add... |
630 |
gfs2_trans_add_bh(dip->i_gl, bh, 1); |
b3b94faa5 [GFS2] The core o... |
631 632 633 634 635 636 |
/* If there is no prev entry, this is the first entry in the block. The de_rec_len is already as big as it needs to be. Just zero out the inode number and return. */ if (!prev) { |
5e7d65cd9 [GFS2] Make senti... |
637 638 |
cur->de_inum.no_addr = 0; cur->de_inum.no_formal_ino = 0; |
b3b94faa5 [GFS2] The core o... |
639 640 641 642 |
return; } /* Combine this dentry with the previous one. */ |
fc69d0d33 [GFS2] Change ond... |
643 644 |
prev_rec_len = be16_to_cpu(prev->de_rec_len); cur_rec_len = be16_to_cpu(cur->de_rec_len); |
b3b94faa5 [GFS2] The core o... |
645 646 647 648 649 650 651 |
if ((char *)prev + prev_rec_len != (char *)cur) gfs2_consist_inode(dip); if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size) gfs2_consist_inode(dip); prev_rec_len += cur_rec_len; |
fc69d0d33 [GFS2] Change ond... |
652 |
prev->de_rec_len = cpu_to_be16(prev_rec_len); |
b3b94faa5 [GFS2] The core o... |
653 |
} |
c752666c1 [GFS2] Fix bug in... |
654 655 656 |
/* * Takes a dent from which to grab space as an argument. Returns the * newly created dent. |
b3b94faa5 [GFS2] The core o... |
657 |
*/ |
08bc2dbc7 [GFS2] [-mm patch... |
658 659 660 661 |
static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, struct gfs2_dirent *dent, const struct qstr *name, struct buffer_head *bh) |
b3b94faa5 [GFS2] The core o... |
662 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
663 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
664 665 |
struct gfs2_dirent *ndent; unsigned offset = 0, totlen; |
5e7d65cd9 [GFS2] Make senti... |
666 |
if (!gfs2_dirent_sentinel(dent)) |
c752666c1 [GFS2] Fix bug in... |
667 668 669 670 671 672 673 674 |
offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); totlen = be16_to_cpu(dent->de_rec_len); BUG_ON(offset + name->len > totlen); gfs2_trans_add_bh(ip->i_gl, bh, 1); ndent = (struct gfs2_dirent *)((char *)dent + offset); dent->de_rec_len = cpu_to_be16(offset); gfs2_qstr2dirent(name, totlen - offset, ndent); return ndent; |
b3b94faa5 [GFS2] The core o... |
675 |
} |
c752666c1 [GFS2] Fix bug in... |
676 677 678 |
static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, struct buffer_head *bh, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
679 680 |
{ struct gfs2_dirent *dent; |
907b9bceb [GFS2/DLM] Fix tr... |
681 |
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
71b86f562 [GFS2] Further up... |
682 |
gfs2_dirent_find_space, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
683 684 685 |
if (!dent || IS_ERR(dent)) return dent; return gfs2_init_dirent(inode, dent, name, bh); |
b3b94faa5 [GFS2] The core o... |
686 |
} |
cd915493f [GFS2] Change all... |
687 |
static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, |
b3b94faa5 [GFS2] The core o... |
688 689 690 |
struct buffer_head **bhp) { int error; |
7276b3b0c [GFS2] Tidy up me... |
691 |
error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); |
feaa7bba0 [GFS2] Fix unlink... |
692 693 694 |
if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { /* printk(KERN_INFO "block num=%llu ", leaf_no); */ |
b3b94faa5 [GFS2] The core o... |
695 |
error = -EIO; |
feaa7bba0 [GFS2] Fix unlink... |
696 |
} |
b3b94faa5 [GFS2] The core o... |
697 698 699 700 701 702 703 704 705 706 707 708 |
return error; } /** * get_leaf_nr - Get a leaf number associated with the index * @dip: The GFS2 inode * @index: * @leaf_out: * * Returns: 0 on success, error code otherwise */ |
cd915493f [GFS2] Change all... |
709 710 |
static int get_leaf_nr(struct gfs2_inode *dip, u32 index, u64 *leaf_out) |
b3b94faa5 [GFS2] The core o... |
711 |
{ |
17d539f04 GFS2: Cache dir h... |
712 |
__be64 *hash; |
b3b94faa5 [GFS2] The core o... |
713 |
|
17d539f04 GFS2: Cache dir h... |
714 715 716 717 |
hash = gfs2_dir_get_hash_table(dip); if (IS_ERR(hash)) return PTR_ERR(hash); *leaf_out = be64_to_cpu(*(hash + index)); |
b3b94faa5 [GFS2] The core o... |
718 719 |
return 0; } |
cd915493f [GFS2] Change all... |
720 |
static int get_first_leaf(struct gfs2_inode *dip, u32 index, |
b3b94faa5 [GFS2] The core o... |
721 722 |
struct buffer_head **bh_out) { |
cd915493f [GFS2] Change all... |
723 |
u64 leaf_no; |
b3b94faa5 [GFS2] The core o... |
724 725 726 727 728 729 730 731 |
int error; error = get_leaf_nr(dip, index, &leaf_no); if (!error) error = get_leaf(dip, leaf_no, bh_out); return error; } |
c752666c1 [GFS2] Fix bug in... |
732 733 734 735 |
static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, const struct qstr *name, gfs2_dscan_t scan, struct buffer_head **pbh) |
b3b94faa5 [GFS2] The core o... |
736 |
{ |
c752666c1 [GFS2] Fix bug in... |
737 738 |
struct buffer_head *bh; struct gfs2_dirent *dent; |
feaa7bba0 [GFS2] Fix unlink... |
739 |
struct gfs2_inode *ip = GFS2_I(inode); |
b3b94faa5 [GFS2] The core o... |
740 |
int error; |
383f01fbf GFS2: Banish stru... |
741 |
if (ip->i_diskflags & GFS2_DIF_EXHASH) { |
c752666c1 [GFS2] Fix bug in... |
742 |
struct gfs2_leaf *leaf; |
9a0045088 [GFS2] Shrink & r... |
743 |
unsigned hsize = 1 << ip->i_depth; |
c752666c1 [GFS2] Fix bug in... |
744 745 |
unsigned index; u64 ln; |
a2e0f7993 GFS2: Remove i_di... |
746 |
if (hsize * sizeof(u64) != i_size_read(inode)) { |
c752666c1 [GFS2] Fix bug in... |
747 748 749 |
gfs2_consist_inode(ip); return ERR_PTR(-EIO); } |
907b9bceb [GFS2/DLM] Fix tr... |
750 |
|
9a0045088 [GFS2] Shrink & r... |
751 |
index = name->hash >> (32 - ip->i_depth); |
c752666c1 [GFS2] Fix bug in... |
752 753 754 755 756 |
error = get_first_leaf(ip, index, &bh); if (error) return ERR_PTR(error); do { dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
71b86f562 [GFS2] Further up... |
757 |
scan, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
758 759 760 761 |
if (dent) goto got_dent; leaf = (struct gfs2_leaf *)bh->b_data; ln = be64_to_cpu(leaf->lf_next); |
f4154ea03 [GFS2] Update jou... |
762 |
brelse(bh); |
c752666c1 [GFS2] Fix bug in... |
763 764 |
if (!ln) break; |
907b9bceb [GFS2/DLM] Fix tr... |
765 |
|
c752666c1 [GFS2] Fix bug in... |
766 767 |
error = get_leaf(ip, ln, &bh); } while(!error); |
b3b94faa5 [GFS2] The core o... |
768 |
|
c752666c1 [GFS2] Fix bug in... |
769 |
return error ? ERR_PTR(error) : NULL; |
b3b94faa5 [GFS2] The core o... |
770 |
} |
b3b94faa5 [GFS2] The core o... |
771 |
|
907b9bceb [GFS2/DLM] Fix tr... |
772 |
|
c752666c1 [GFS2] Fix bug in... |
773 774 775 |
error = gfs2_meta_inode_buffer(ip, &bh); if (error) return ERR_PTR(error); |
71b86f562 [GFS2] Further up... |
776 |
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
777 |
got_dent: |
f4154ea03 [GFS2] Update jou... |
778 |
if (unlikely(dent == NULL || IS_ERR(dent))) { |
ed3865079 [GFS2] Finally ge... |
779 780 781 |
brelse(bh); bh = NULL; } |
c752666c1 [GFS2] Fix bug in... |
782 783 784 |
*pbh = bh; return dent; } |
b3b94faa5 [GFS2] The core o... |
785 |
|
c752666c1 [GFS2] Fix bug in... |
786 787 |
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { |
feaa7bba0 [GFS2] Fix unlink... |
788 |
struct gfs2_inode *ip = GFS2_I(inode); |
b45e41d7d [GFS2] Add extent... |
789 |
unsigned int n = 1; |
090109783 GFS2: Improve res... |
790 791 792 |
u64 bn; int error; struct buffer_head *bh; |
c752666c1 [GFS2] Fix bug in... |
793 794 |
struct gfs2_leaf *leaf; struct gfs2_dirent *dent; |
71b86f562 [GFS2] Further up... |
795 |
struct qstr name = { .name = "", .len = 0, .hash = 0 }; |
090109783 GFS2: Improve res... |
796 |
|
6e87ed0fc GFS2: move toward... |
797 |
error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); |
090109783 GFS2: Improve res... |
798 799 800 |
if (error) return NULL; bh = gfs2_meta_new(ip->i_gl, bn); |
c752666c1 [GFS2] Fix bug in... |
801 802 |
if (!bh) return NULL; |
090109783 GFS2: Improve res... |
803 |
|
5731be53e [GFS2] Update gfs... |
804 |
gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); |
c752666c1 [GFS2] Fix bug in... |
805 806 807 808 |
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); leaf = (struct gfs2_leaf *)bh->b_data; leaf->lf_depth = cpu_to_be16(depth); |
2bdbc5d73 [GFS2] Directory ... |
809 |
leaf->lf_entries = 0; |
a2d7d021d [GFS2] gfs2 endia... |
810 |
leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); |
2bdbc5d73 [GFS2] Directory ... |
811 |
leaf->lf_next = 0; |
c752666c1 [GFS2] Fix bug in... |
812 813 |
memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); dent = (struct gfs2_dirent *)(leaf+1); |
71b86f562 [GFS2] Further up... |
814 |
gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); |
c752666c1 [GFS2] Fix bug in... |
815 816 |
*pbh = bh; return leaf; |
b3b94faa5 [GFS2] The core o... |
817 818 819 820 821 822 823 824 |
} /** * dir_make_exhash - Convert a stuffed directory into an ExHash directory * @dip: The GFS2 inode * * Returns: 0 on success, error code otherwise */ |
c752666c1 [GFS2] Fix bug in... |
825 |
static int dir_make_exhash(struct inode *inode) |
b3b94faa5 [GFS2] The core o... |
826 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
827 828 |
struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); |
b3b94faa5 [GFS2] The core o... |
829 |
struct gfs2_dirent *dent; |
c752666c1 [GFS2] Fix bug in... |
830 |
struct qstr args; |
b3b94faa5 [GFS2] The core o... |
831 832 833 |
struct buffer_head *bh, *dibh; struct gfs2_leaf *leaf; int y; |
cd915493f [GFS2] Change all... |
834 |
u32 x; |
b44b84d76 [GFS2] gfs2 misc ... |
835 836 |
__be64 *lp; u64 bn; |
b3b94faa5 [GFS2] The core o... |
837 838 839 840 841 |
int error; error = gfs2_meta_inode_buffer(dip, &dibh); if (error) return error; |
b3b94faa5 [GFS2] The core o... |
842 |
/* Turn over a new leaf */ |
c752666c1 [GFS2] Fix bug in... |
843 844 845 846 |
leaf = new_leaf(inode, &bh, 0); if (!leaf) return -ENOSPC; bn = bh->b_blocknr; |
b3b94faa5 [GFS2] The core o... |
847 |
|
ad6203f2b GFS2: Move "entri... |
848 849 |
gfs2_assert(sdp, dip->i_entries < (1 << 16)); leaf->lf_entries = cpu_to_be16(dip->i_entries); |
b3b94faa5 [GFS2] The core o... |
850 851 852 853 854 855 856 857 858 |
/* Copy dirents */ gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh, sizeof(struct gfs2_dinode)); /* Find last entry */ x = 0; |
c752666c1 [GFS2] Fix bug in... |
859 860 861 |
args.len = bh->b_size - sizeof(struct gfs2_dinode) + sizeof(struct gfs2_leaf); args.name = bh->b_data; |
feaa7bba0 [GFS2] Fix unlink... |
862 |
dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size, |
71b86f562 [GFS2] Further up... |
863 |
gfs2_dirent_last, &args, NULL); |
c752666c1 [GFS2] Fix bug in... |
864 865 866 867 868 869 870 871 872 |
if (!dent) { brelse(bh); brelse(dibh); return -EIO; } if (IS_ERR(dent)) { brelse(bh); brelse(dibh); return PTR_ERR(dent); |
b3b94faa5 [GFS2] The core o... |
873 |
} |
b3b94faa5 [GFS2] The core o... |
874 875 876 |
/* Adjust the last dirent's record length (Remember that dent still points to the last entry.) */ |
4dd651adb [GFS2] Fix the bu... |
877 |
dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) + |
b3b94faa5 [GFS2] The core o... |
878 |
sizeof(struct gfs2_dinode) - |
4dd651adb [GFS2] Fix the bu... |
879 |
sizeof(struct gfs2_leaf)); |
b3b94faa5 [GFS2] The core o... |
880 881 882 883 884 |
brelse(bh); /* We're done with the new leaf block, now setup the new hash table. */ |
d4e9c4c3b [GFS2] Add an add... |
885 |
gfs2_trans_add_bh(dip->i_gl, dibh, 1); |
b3b94faa5 [GFS2] The core o... |
886 |
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
b44b84d76 [GFS2] gfs2 misc ... |
887 |
lp = (__be64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); |
b3b94faa5 [GFS2] The core o... |
888 889 890 |
for (x = sdp->sd_hash_ptrs; x--; lp++) *lp = cpu_to_be64(bn); |
a2e0f7993 GFS2: Remove i_di... |
891 |
i_size_write(inode, sdp->sd_sb.sb_bsize / 2); |
77658aad2 [GFS2] Eliminate ... |
892 |
gfs2_add_inode_blocks(&dip->i_inode, 1); |
383f01fbf GFS2: Banish stru... |
893 |
dip->i_diskflags |= GFS2_DIF_EXHASH; |
b3b94faa5 [GFS2] The core o... |
894 895 |
for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; |
9a0045088 [GFS2] Shrink & r... |
896 |
dip->i_depth = y; |
b3b94faa5 [GFS2] The core o... |
897 |
|
539e5d6b7 [GFS2] Change arg... |
898 |
gfs2_dinode_out(dip, dibh->b_data); |
b3b94faa5 [GFS2] The core o... |
899 900 901 902 903 904 905 906 907 908 909 910 911 912 |
brelse(dibh); return 0; } /** * dir_split_leaf - Split a leaf block into two * @dip: The GFS2 inode * @index: * @leaf_no: * * Returns: 0 on success, error code on failure */ |
c752666c1 [GFS2] Fix bug in... |
913 |
static int dir_split_leaf(struct inode *inode, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
914 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
915 |
struct gfs2_inode *dip = GFS2_I(inode); |
b3b94faa5 [GFS2] The core o... |
916 917 |
struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; |
4da3c6463 [GFS2] Fix a coup... |
918 |
struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new; |
cd915493f [GFS2] Change all... |
919 |
u32 start, len, half_len, divider; |
b44b84d76 [GFS2] gfs2 misc ... |
920 921 |
u64 bn, leaf_no; __be64 *lp; |
cd915493f [GFS2] Change all... |
922 |
u32 index; |
b3b94faa5 [GFS2] The core o... |
923 924 |
int x, moved = 0; int error; |
9a0045088 [GFS2] Shrink & r... |
925 |
index = name->hash >> (32 - dip->i_depth); |
c752666c1 [GFS2] Fix bug in... |
926 927 928 |
error = get_leaf_nr(dip, index, &leaf_no); if (error) return error; |
b3b94faa5 [GFS2] The core o... |
929 930 |
/* Get the old leaf block */ |
b3b94faa5 [GFS2] The core o... |
931 932 |
error = get_leaf(dip, leaf_no, &obh); if (error) |
e90deff53 [GFS2] Fix bug in... |
933 |
return error; |
b3b94faa5 [GFS2] The core o... |
934 |
|
b3b94faa5 [GFS2] The core o... |
935 |
oleaf = (struct gfs2_leaf *)obh->b_data; |
9a0045088 [GFS2] Shrink & r... |
936 |
if (dip->i_depth == be16_to_cpu(oleaf->lf_depth)) { |
e90deff53 [GFS2] Fix bug in... |
937 938 939 940 941 |
brelse(obh); return 1; /* can't split */ } gfs2_trans_add_bh(dip->i_gl, obh, 1); |
b3b94faa5 [GFS2] The core o... |
942 |
|
c752666c1 [GFS2] Fix bug in... |
943 944 945 946 947 948 |
nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1); if (!nleaf) { brelse(obh); return -ENOSPC; } bn = nbh->b_blocknr; |
b3b94faa5 [GFS2] The core o... |
949 |
|
c752666c1 [GFS2] Fix bug in... |
950 |
/* Compute the start and len of leaf pointers in the hash table. */ |
9a0045088 [GFS2] Shrink & r... |
951 |
len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth)); |
b3b94faa5 [GFS2] The core o... |
952 953 |
half_len = len >> 1; if (!half_len) { |
9a0045088 [GFS2] Shrink & r... |
954 955 |
printk(KERN_WARNING "i_depth %u lf_depth %u index %u ", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); |
b3b94faa5 [GFS2] The core o... |
956 957 958 959 960 961 962 963 964 965 |
gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; } start = (index & ~(len - 1)); /* Change the pointers. Don't bother distinguishing stuffed from non-stuffed. This code is complicated enough already. */ |
4244b52e1 GFS2: remove depe... |
966 967 968 969 970 |
lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS); if (!lp) { error = -ENOMEM; goto fail_brelse; } |
b3b94faa5 [GFS2] The core o... |
971 |
/* Change the pointers */ |
b3b94faa5 [GFS2] The core o... |
972 973 |
for (x = 0; x < half_len; x++) lp[x] = cpu_to_be64(bn); |
17d539f04 GFS2: Cache dir h... |
974 |
gfs2_dir_hash_inval(dip); |
cd915493f [GFS2] Change all... |
975 976 977 |
error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64), half_len * sizeof(u64)); if (error != half_len * sizeof(u64)) { |
b3b94faa5 [GFS2] The core o... |
978 979 980 981 982 983 984 985 |
if (error >= 0) error = -EIO; goto fail_lpfree; } kfree(lp); /* Compute the divider */ |
9a0045088 [GFS2] Shrink & r... |
986 |
divider = (start + half_len) << (32 - dip->i_depth); |
b3b94faa5 [GFS2] The core o... |
987 988 |
/* Copy the entries */ |
1579343a7 GFS2: Remove dire... |
989 |
dent = (struct gfs2_dirent *)(obh->b_data + sizeof(struct gfs2_leaf)); |
b3b94faa5 [GFS2] The core o... |
990 991 992 993 994 |
do { next = dent; if (dirent_next(dip, obh, &next)) next = NULL; |
5e7d65cd9 [GFS2] Make senti... |
995 |
if (!gfs2_dirent_sentinel(dent) && |
b3b94faa5 [GFS2] The core o... |
996 |
be32_to_cpu(dent->de_hash) < divider) { |
c752666c1 [GFS2] Fix bug in... |
997 998 999 1000 |
struct qstr str; str.name = (char*)(dent+1); str.len = be16_to_cpu(dent->de_name_len); str.hash = be32_to_cpu(dent->de_hash); |
71b86f562 [GFS2] Further up... |
1001 |
new = gfs2_dirent_alloc(inode, nbh, &str); |
c752666c1 [GFS2] Fix bug in... |
1002 1003 1004 1005 |
if (IS_ERR(new)) { error = PTR_ERR(new); break; } |
b3b94faa5 [GFS2] The core o... |
1006 1007 |
new->de_inum = dent->de_inum; /* No endian worries */ |
b3b94faa5 [GFS2] The core o... |
1008 |
new->de_type = dent->de_type; /* No endian worries */ |
bb16b342b [GFS2] be*_add_cp... |
1009 |
be16_add_cpu(&nleaf->lf_entries, 1); |
b3b94faa5 [GFS2] The core o... |
1010 1011 1012 1013 1014 |
dirent_del(dip, obh, prev, dent); if (!oleaf->lf_entries) gfs2_consist_inode(dip); |
bb16b342b [GFS2] be*_add_cp... |
1015 |
be16_add_cpu(&oleaf->lf_entries, -1); |
b3b94faa5 [GFS2] The core o... |
1016 1017 1018 1019 1020 |
if (!prev) prev = dent; moved = 1; |
c752666c1 [GFS2] Fix bug in... |
1021 |
} else { |
b3b94faa5 [GFS2] The core o... |
1022 |
prev = dent; |
c752666c1 [GFS2] Fix bug in... |
1023 |
} |
b3b94faa5 [GFS2] The core o... |
1024 |
dent = next; |
c752666c1 [GFS2] Fix bug in... |
1025 |
} while (dent); |
b3b94faa5 [GFS2] The core o... |
1026 |
|
c752666c1 [GFS2] Fix bug in... |
1027 |
oleaf->lf_depth = nleaf->lf_depth; |
b3b94faa5 [GFS2] The core o... |
1028 1029 |
error = gfs2_meta_inode_buffer(dip, &dibh); |
feaa7bba0 [GFS2] Fix unlink... |
1030 |
if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { |
382e6e256 [GFS2] Add a miss... |
1031 |
gfs2_trans_add_bh(dip->i_gl, dibh, 1); |
77658aad2 [GFS2] Eliminate ... |
1032 |
gfs2_add_inode_blocks(&dip->i_inode, 1); |
539e5d6b7 [GFS2] Change arg... |
1033 |
gfs2_dinode_out(dip, dibh->b_data); |
b3b94faa5 [GFS2] The core o... |
1034 1035 1036 1037 1038 1039 1040 |
brelse(dibh); } brelse(obh); brelse(nbh); return error; |
e90deff53 [GFS2] Fix bug in... |
1041 |
fail_lpfree: |
b3b94faa5 [GFS2] The core o... |
1042 |
kfree(lp); |
e90deff53 [GFS2] Fix bug in... |
1043 |
fail_brelse: |
b3b94faa5 [GFS2] The core o... |
1044 |
brelse(obh); |
b3b94faa5 [GFS2] The core o... |
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
brelse(nbh); return error; } /** * dir_double_exhash - Double size of ExHash table * @dip: The GFS2 dinode * * Returns: 0 on success, error code on failure */ static int dir_double_exhash(struct gfs2_inode *dip) { |
b3b94faa5 [GFS2] The core o... |
1058 |
struct buffer_head *dibh; |
cd915493f [GFS2] Change all... |
1059 |
u32 hsize; |
17d539f04 GFS2: Cache dir h... |
1060 1061 1062 |
u32 hsize_bytes; __be64 *hc; __be64 *hc2, *h; |
b3b94faa5 [GFS2] The core o... |
1063 1064 |
int x; int error = 0; |
9a0045088 [GFS2] Shrink & r... |
1065 |
hsize = 1 << dip->i_depth; |
17d539f04 GFS2: Cache dir h... |
1066 |
hsize_bytes = hsize * sizeof(__be64); |
b3b94faa5 [GFS2] The core o... |
1067 |
|
17d539f04 GFS2: Cache dir h... |
1068 1069 1070 |
hc = gfs2_dir_get_hash_table(dip); if (IS_ERR(hc)) return PTR_ERR(hc); |
b3b94faa5 [GFS2] The core o... |
1071 |
|
17d539f04 GFS2: Cache dir h... |
1072 1073 |
h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS); if (!hc2) |
4244b52e1 GFS2: remove depe... |
1074 |
return -ENOMEM; |
b3b94faa5 [GFS2] The core o... |
1075 |
|
17d539f04 GFS2: Cache dir h... |
1076 1077 1078 |
error = gfs2_meta_inode_buffer(dip, &dibh); if (error) goto out_kfree; |
b3b94faa5 [GFS2] The core o... |
1079 |
|
17d539f04 GFS2: Cache dir h... |
1080 1081 1082 1083 |
for (x = 0; x < hsize; x++) { *h++ = *hc; *h++ = *hc; hc++; |
b3b94faa5 [GFS2] The core o... |
1084 |
} |
17d539f04 GFS2: Cache dir h... |
1085 1086 1087 |
error = gfs2_dir_write_data(dip, (char *)hc2, 0, hsize_bytes * 2); if (error != (hsize_bytes * 2)) goto fail; |
b3b94faa5 [GFS2] The core o... |
1088 |
|
17d539f04 GFS2: Cache dir h... |
1089 1090 1091 1092 1093 1094 |
gfs2_dir_hash_inval(dip); dip->i_hash_cache = hc2; dip->i_depth++; gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); return 0; |
b3b94faa5 [GFS2] The core o... |
1095 |
|
a91ea69ff [GFS2] Align all ... |
1096 |
fail: |
17d539f04 GFS2: Cache dir h... |
1097 1098 1099 1100 1101 1102 1103 |
/* Replace original hash table & size */ gfs2_dir_write_data(dip, (char *)hc, 0, hsize_bytes); i_size_write(&dip->i_inode, hsize_bytes); gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); out_kfree: kfree(hc2); |
b3b94faa5 [GFS2] The core o... |
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 |
return error; } /** * compare_dents - compare directory entries by hash value * @a: first dent * @b: second dent * * When comparing the hash entries of @a to @b: * gt: returns 1 * lt: returns -1 * eq: returns 0 */ static int compare_dents(const void *a, const void *b) { |
2bdbc5d73 [GFS2] Directory ... |
1120 |
const struct gfs2_dirent *dent_a, *dent_b; |
cd915493f [GFS2] Change all... |
1121 |
u32 hash_a, hash_b; |
b3b94faa5 [GFS2] The core o... |
1122 |
int ret = 0; |
2bdbc5d73 [GFS2] Directory ... |
1123 |
dent_a = *(const struct gfs2_dirent **)a; |
c752666c1 [GFS2] Fix bug in... |
1124 |
hash_a = be32_to_cpu(dent_a->de_hash); |
b3b94faa5 [GFS2] The core o... |
1125 |
|
2bdbc5d73 [GFS2] Directory ... |
1126 |
dent_b = *(const struct gfs2_dirent **)b; |
c752666c1 [GFS2] Fix bug in... |
1127 |
hash_b = be32_to_cpu(dent_b->de_hash); |
b3b94faa5 [GFS2] The core o... |
1128 1129 1130 1131 1132 1133 |
if (hash_a > hash_b) ret = 1; else if (hash_a < hash_b) ret = -1; else { |
4dd651adb [GFS2] Fix the bu... |
1134 1135 |
unsigned int len_a = be16_to_cpu(dent_a->de_name_len); unsigned int len_b = be16_to_cpu(dent_b->de_name_len); |
b3b94faa5 [GFS2] The core o... |
1136 1137 1138 1139 1140 1141 |
if (len_a > len_b) ret = 1; else if (len_a < len_b) ret = -1; else |
2bdbc5d73 [GFS2] Directory ... |
1142 |
ret = memcmp(dent_a + 1, dent_b + 1, len_a); |
b3b94faa5 [GFS2] The core o... |
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
} return ret; } /** * do_filldir_main - read out directory entries * @dip: The GFS2 inode * @offset: The offset in the file to read from * @opaque: opaque data to pass to filldir * @filldir: The function to pass entries to * @darr: an array of struct gfs2_dirent pointers to read * @entries: the number of entries in darr * @copied: pointer to int that's non-zero if a entry has been copied out * * Jump through some hoops to make sure that if there are hash collsions, * they are read out at the beginning of a buffer. We want to minimize * the possibility that they will fall into different readdir buffers or * that someone will want to seek to that location. * * Returns: errno, >0 on exception from filldir */ |
cd915493f [GFS2] Change all... |
1165 |
static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, |
3699e3a44 [GFS2] Clean up/s... |
1166 |
void *opaque, filldir_t filldir, |
cd915493f [GFS2] Change all... |
1167 |
const struct gfs2_dirent **darr, u32 entries, |
b3b94faa5 [GFS2] The core o... |
1168 1169 |
int *copied) { |
71b86f562 [GFS2] Further up... |
1170 |
const struct gfs2_dirent *dent, *dent_next; |
cd915493f [GFS2] Change all... |
1171 |
u64 off, off_next; |
b3b94faa5 [GFS2] The core o... |
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
unsigned int x, y; int run = 0; int error = 0; sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL); dent_next = darr[0]; off_next = be32_to_cpu(dent_next->de_hash); off_next = gfs2_disk_hash2offset(off_next); for (x = 0, y = 1; x < entries; x++, y++) { dent = dent_next; off = off_next; if (y < entries) { dent_next = darr[y]; off_next = be32_to_cpu(dent_next->de_hash); off_next = gfs2_disk_hash2offset(off_next); if (off < *offset) continue; *offset = off; if (off_next == off) { if (*copied && !run) return 1; run = 1; } else run = 0; } else { if (off < *offset) continue; *offset = off; } |
2bdbc5d73 [GFS2] Directory ... |
1206 |
error = filldir(opaque, (const char *)(dent + 1), |
4dd651adb [GFS2] Fix the bu... |
1207 |
be16_to_cpu(dent->de_name_len), |
3699e3a44 [GFS2] Clean up/s... |
1208 |
off, be64_to_cpu(dent->de_inum.no_addr), |
4dd651adb [GFS2] Fix the bu... |
1209 |
be16_to_cpu(dent->de_type)); |
b3b94faa5 [GFS2] The core o... |
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 |
if (error) return 1; *copied = 1; } /* Increment the *offset by one, so the next time we come into the do_filldir fxn, we get the next entry instead of the last one in the current leaf */ (*offset)++; return 0; } |
d2a97a4e9 GFS2: Use kmalloc... |
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 |
static void *gfs2_alloc_sort_buffer(unsigned size) { void *ptr = NULL; if (size < KMALLOC_MAX_SIZE) ptr = kmalloc(size, GFP_NOFS | __GFP_NOWARN); if (!ptr) ptr = __vmalloc(size, GFP_NOFS, PAGE_KERNEL); return ptr; } static void gfs2_free_sort_buffer(void *ptr) { if (is_vmalloc_addr(ptr)) vfree(ptr); else kfree(ptr); } |
71b86f562 [GFS2] Further up... |
1242 |
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, |
3699e3a44 [GFS2] Clean up/s... |
1243 1244 |
filldir_t filldir, int *copied, unsigned *depth, u64 leaf_no) |
b3b94faa5 [GFS2] The core o... |
1245 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1246 |
struct gfs2_inode *ip = GFS2_I(inode); |
bdd19a22f [GFS2] Patch to d... |
1247 |
struct gfs2_sbd *sdp = GFS2_SB(inode); |
71b86f562 [GFS2] Further up... |
1248 1249 |
struct buffer_head *bh; struct gfs2_leaf *lf; |
bdd19a22f [GFS2] Patch to d... |
1250 |
unsigned entries = 0, entries2 = 0; |
71b86f562 [GFS2] Further up... |
1251 1252 1253 1254 1255 1256 1257 |
unsigned leaves = 0; const struct gfs2_dirent **darr, *dent; struct dirent_gather g; struct buffer_head **larr; int leaf = 0; int error, i; u64 lfn = leaf_no; |
b3b94faa5 [GFS2] The core o... |
1258 |
|
b3b94faa5 [GFS2] The core o... |
1259 |
do { |
71b86f562 [GFS2] Further up... |
1260 |
error = get_leaf(ip, lfn, &bh); |
b3b94faa5 [GFS2] The core o... |
1261 |
if (error) |
71b86f562 [GFS2] Further up... |
1262 1263 1264 1265 1266 1267 1268 1269 1270 |
goto out; lf = (struct gfs2_leaf *)bh->b_data; if (leaves == 0) *depth = be16_to_cpu(lf->lf_depth); entries += be16_to_cpu(lf->lf_entries); leaves++; lfn = be64_to_cpu(lf->lf_next); brelse(bh); } while(lfn); |
b3b94faa5 [GFS2] The core o... |
1271 1272 1273 |
if (!entries) return 0; |
71b86f562 [GFS2] Further up... |
1274 |
error = -ENOMEM; |
bdd19a22f [GFS2] Patch to d... |
1275 1276 1277 1278 1279 1280 |
/* * The extra 99 entries are not normally used, but are a buffer * zone in case the number of entries in the leaf is corrupt. * 99 is the maximum number of entries that can fit in a single * leaf block. */ |
d2a97a4e9 GFS2: Use kmalloc... |
1281 |
larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *)); |
71b86f562 [GFS2] Further up... |
1282 1283 1284 1285 1286 1287 |
if (!larr) goto out; darr = (const struct gfs2_dirent **)(larr + leaves); g.pdent = darr; g.offset = 0; lfn = leaf_no; |
b3b94faa5 [GFS2] The core o... |
1288 |
|
71b86f562 [GFS2] Further up... |
1289 1290 |
do { error = get_leaf(ip, lfn, &bh); |
b3b94faa5 [GFS2] The core o... |
1291 |
if (error) |
d2a97a4e9 GFS2: Use kmalloc... |
1292 |
goto out_free; |
71b86f562 [GFS2] Further up... |
1293 1294 1295 |
lf = (struct gfs2_leaf *)bh->b_data; lfn = be64_to_cpu(lf->lf_next); if (lf->lf_entries) { |
bdd19a22f [GFS2] Patch to d... |
1296 |
entries2 += be16_to_cpu(lf->lf_entries); |
71b86f562 [GFS2] Further up... |
1297 1298 1299 |
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_gather, NULL, &g); error = PTR_ERR(dent); |
bdd19a22f [GFS2] Patch to d... |
1300 |
if (IS_ERR(dent)) |
d2a97a4e9 GFS2: Use kmalloc... |
1301 |
goto out_free; |
bdd19a22f [GFS2] Patch to d... |
1302 |
if (entries2 != g.offset) { |
f391a4ead [GFS2] printk war... |
1303 1304 1305 1306 1307 1308 |
fs_warn(sdp, "Number of entries corrupt in dir " "leaf %llu, entries2 (%u) != " "g.offset (%u) ", (unsigned long long)bh->b_blocknr, entries2, g.offset); |
bdd19a22f [GFS2] Patch to d... |
1309 1310 |
error = -EIO; |
d2a97a4e9 GFS2: Use kmalloc... |
1311 |
goto out_free; |
71b86f562 [GFS2] Further up... |
1312 1313 1314 |
} error = 0; larr[leaf++] = bh; |
b3b94faa5 [GFS2] The core o... |
1315 |
} else { |
71b86f562 [GFS2] Further up... |
1316 |
brelse(bh); |
b3b94faa5 [GFS2] The core o... |
1317 |
} |
71b86f562 [GFS2] Further up... |
1318 |
} while(lfn); |
b3b94faa5 [GFS2] The core o... |
1319 |
|
bdd19a22f [GFS2] Patch to d... |
1320 |
BUG_ON(entries2 != entries); |
71b86f562 [GFS2] Further up... |
1321 |
error = do_filldir_main(ip, offset, opaque, filldir, darr, |
b3b94faa5 [GFS2] The core o... |
1322 |
entries, copied); |
d2a97a4e9 GFS2: Use kmalloc... |
1323 |
out_free: |
71b86f562 [GFS2] Further up... |
1324 1325 |
for(i = 0; i < leaf; i++) brelse(larr[i]); |
d2a97a4e9 GFS2: Use kmalloc... |
1326 |
gfs2_free_sort_buffer(larr); |
71b86f562 [GFS2] Further up... |
1327 |
out: |
b3b94faa5 [GFS2] The core o... |
1328 1329 |
return error; } |
79c4c379c GFS2: f_ra is alw... |
1330 1331 |
/** * gfs2_dir_readahead - Issue read-ahead requests for leaf blocks. |
dfe4d34b3 GFS2: Add readahe... |
1332 1333 1334 1335 |
* * Note: we can't calculate each index like dir_e_read can because we don't * have the leaf, and therefore we don't have the depth, and therefore we * don't have the length. So we have to just read enough ahead to make up |
79c4c379c GFS2: f_ra is alw... |
1336 1337 |
* for the loss of information. */ |
dfe4d34b3 GFS2: Add readahe... |
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index, struct file_ra_state *f_ra) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_glock *gl = ip->i_gl; struct buffer_head *bh; u64 blocknr = 0, last; unsigned count; /* First check if we've already read-ahead for the whole range. */ |
79c4c379c GFS2: f_ra is alw... |
1348 |
if (index + MAX_RA_BLOCKS < f_ra->start) |
dfe4d34b3 GFS2: Add readahe... |
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 |
return; f_ra->start = max((pgoff_t)index, f_ra->start); for (count = 0; count < MAX_RA_BLOCKS; count++) { if (f_ra->start >= hsize) /* if exceeded the hash table */ break; last = blocknr; blocknr = be64_to_cpu(ip->i_hash_cache[f_ra->start]); f_ra->start++; if (blocknr == last) continue; bh = gfs2_getbuf(gl, blocknr, 1); if (trylock_buffer(bh)) { if (buffer_uptodate(bh)) { unlock_buffer(bh); brelse(bh); continue; } bh->b_end_io = end_buffer_read_sync; submit_bh(READA | REQ_META, bh); continue; } brelse(bh); } } |
17d539f04 GFS2: Cache dir h... |
1376 |
|
b3b94faa5 [GFS2] The core o... |
1377 |
/** |
c752666c1 [GFS2] Fix bug in... |
1378 1379 1380 1381 1382 |
* dir_e_read - Reads the entries from a directory into a filldir buffer * @dip: dinode pointer * @offset: the hash of the last entry read shifted to the right once * @opaque: buffer for the filldir function to fill * @filldir: points to the filldir function to use |
b3b94faa5 [GFS2] The core o... |
1383 |
* |
c752666c1 [GFS2] Fix bug in... |
1384 |
* Returns: errno |
b3b94faa5 [GFS2] The core o... |
1385 |
*/ |
cd915493f [GFS2] Change all... |
1386 |
static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, |
dfe4d34b3 GFS2: Add readahe... |
1387 |
filldir_t filldir, struct file_ra_state *f_ra) |
b3b94faa5 [GFS2] The core o... |
1388 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1389 |
struct gfs2_inode *dip = GFS2_I(inode); |
cd915493f [GFS2] Change all... |
1390 |
u32 hsize, len = 0; |
cd915493f [GFS2] Change all... |
1391 |
u32 hash, index; |
b44b84d76 [GFS2] gfs2 misc ... |
1392 |
__be64 *lp; |
c752666c1 [GFS2] Fix bug in... |
1393 1394 |
int copied = 0; int error = 0; |
4da3c6463 [GFS2] Fix a coup... |
1395 |
unsigned depth = 0; |
b3b94faa5 [GFS2] The core o... |
1396 |
|
9a0045088 [GFS2] Shrink & r... |
1397 |
hsize = 1 << dip->i_depth; |
b3b94faa5 [GFS2] The core o... |
1398 |
hash = gfs2_dir_offset2hash(*offset); |
9a0045088 [GFS2] Shrink & r... |
1399 |
index = hash >> (32 - dip->i_depth); |
b3b94faa5 [GFS2] The core o... |
1400 |
|
79c4c379c GFS2: f_ra is alw... |
1401 |
if (dip->i_hash_cache == NULL) |
dfe4d34b3 GFS2: Add readahe... |
1402 |
f_ra->start = 0; |
17d539f04 GFS2: Cache dir h... |
1403 1404 1405 |
lp = gfs2_dir_get_hash_table(dip); if (IS_ERR(lp)) return PTR_ERR(lp); |
b3b94faa5 [GFS2] The core o... |
1406 |
|
dfe4d34b3 GFS2: Add readahe... |
1407 |
gfs2_dir_readahead(inode, hsize, index, f_ra); |
b3b94faa5 [GFS2] The core o... |
1408 |
while (index < hsize) { |
71b86f562 [GFS2] Further up... |
1409 1410 |
error = gfs2_dir_read_leaf(inode, offset, opaque, filldir, &copied, &depth, |
17d539f04 GFS2: Cache dir h... |
1411 |
be64_to_cpu(lp[index])); |
b3b94faa5 [GFS2] The core o... |
1412 |
if (error) |
71b86f562 [GFS2] Further up... |
1413 |
break; |
b3b94faa5 [GFS2] The core o... |
1414 |
|
9a0045088 [GFS2] Shrink & r... |
1415 |
len = 1 << (dip->i_depth - depth); |
b3b94faa5 [GFS2] The core o... |
1416 1417 |
index = (index & ~(len - 1)) + len; } |
71b86f562 [GFS2] Further up... |
1418 1419 |
if (error > 0) error = 0; |
b3b94faa5 [GFS2] The core o... |
1420 1421 |
return error; } |
cd915493f [GFS2] Change all... |
1422 |
int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, |
dfe4d34b3 GFS2: Add readahe... |
1423 |
filldir_t filldir, struct file_ra_state *f_ra) |
b3b94faa5 [GFS2] The core o... |
1424 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1425 |
struct gfs2_inode *dip = GFS2_I(inode); |
bdd19a22f [GFS2] Patch to d... |
1426 |
struct gfs2_sbd *sdp = GFS2_SB(inode); |
71b86f562 [GFS2] Further up... |
1427 1428 |
struct dirent_gather g; const struct gfs2_dirent **darr, *dent; |
b3b94faa5 [GFS2] The core o... |
1429 1430 1431 |
struct buffer_head *dibh; int copied = 0; int error; |
ad6203f2b GFS2: Move "entri... |
1432 |
if (!dip->i_entries) |
71b86f562 [GFS2] Further up... |
1433 |
return 0; |
383f01fbf GFS2: Banish stru... |
1434 |
if (dip->i_diskflags & GFS2_DIF_EXHASH) |
dfe4d34b3 GFS2: Add readahe... |
1435 |
return dir_e_read(inode, offset, opaque, filldir, f_ra); |
71b86f562 [GFS2] Further up... |
1436 |
|
b3b94faa5 [GFS2] The core o... |
1437 1438 1439 1440 |
if (!gfs2_is_stuffed(dip)) { gfs2_consist_inode(dip); return -EIO; } |
b3b94faa5 [GFS2] The core o... |
1441 1442 1443 |
error = gfs2_meta_inode_buffer(dip, &dibh); if (error) return error; |
71b86f562 [GFS2] Further up... |
1444 |
error = -ENOMEM; |
bdd19a22f [GFS2] Patch to d... |
1445 |
/* 96 is max number of dirents which can be stuffed into an inode */ |
16c5f06f1 [GFS2] fix GFP_KE... |
1446 |
darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS); |
71b86f562 [GFS2] Further up... |
1447 1448 1449 1450 1451 1452 1453 1454 1455 |
if (darr) { g.pdent = darr; g.offset = 0; dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size, gfs2_dirent_gather, NULL, &g); if (IS_ERR(dent)) { error = PTR_ERR(dent); goto out; } |
ad6203f2b GFS2: Move "entri... |
1456 |
if (dip->i_entries != g.offset) { |
bdd19a22f [GFS2] Patch to d... |
1457 |
fs_warn(sdp, "Number of entries corrupt in dir %llu, " |
ad6203f2b GFS2: Move "entri... |
1458 1459 |
"ip->i_entries (%u) != g.offset (%u) ", |
dbb7cae2a [GFS2] Clean up i... |
1460 |
(unsigned long long)dip->i_no_addr, |
ad6203f2b GFS2: Move "entri... |
1461 |
dip->i_entries, |
bdd19a22f [GFS2] Patch to d... |
1462 1463 1464 1465 |
g.offset); error = -EIO; goto out; } |
71b86f562 [GFS2] Further up... |
1466 |
error = do_filldir_main(dip, offset, opaque, filldir, darr, |
ad6203f2b GFS2: Move "entri... |
1467 |
dip->i_entries, &copied); |
71b86f562 [GFS2] Further up... |
1468 1469 1470 |
out: kfree(darr); } |
b3b94faa5 [GFS2] The core o... |
1471 1472 1473 1474 1475 1476 1477 |
if (error > 0) error = 0; brelse(dibh); return error; } |
b3b94faa5 [GFS2] The core o... |
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 |
/** * gfs2_dir_search - Search a directory * @dip: The GFS2 inode * @filename: * @inode: * * This routine searches a directory for a file or another directory. * Assumes a glock is held on dip. * * Returns: errno */ |
dbb7cae2a [GFS2] Clean up i... |
1489 |
struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
1490 |
{ |
c752666c1 [GFS2] Fix bug in... |
1491 1492 |
struct buffer_head *bh; struct gfs2_dirent *dent; |
dbb7cae2a [GFS2] Clean up i... |
1493 1494 1495 1496 1497 |
struct inode *inode; dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); if (dent) { if (IS_ERR(dent)) |
e231c2ee6 Convert ERR_PTR(P... |
1498 |
return ERR_CAST(dent); |
bb9bcf061 [GFS2] Obtaining ... |
1499 1500 1501 |
inode = gfs2_inode_lookup(dir->i_sb, be16_to_cpu(dent->de_type), be64_to_cpu(dent->de_inum.no_addr), |
44ad37d69 GFS2: filesystem ... |
1502 |
be64_to_cpu(dent->de_inum.no_formal_ino), 0); |
dbb7cae2a [GFS2] Clean up i... |
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
brelse(bh); return inode; } return ERR_PTR(-ENOENT); } int gfs2_dir_check(struct inode *dir, const struct qstr *name, const struct gfs2_inode *ip) { struct buffer_head *bh; struct gfs2_dirent *dent; int ret = -ENOENT; |
c752666c1 [GFS2] Fix bug in... |
1515 1516 1517 1518 1519 |
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); if (dent) { if (IS_ERR(dent)) return PTR_ERR(dent); |
dbb7cae2a [GFS2] Clean up i... |
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 |
if (ip) { if (be64_to_cpu(dent->de_inum.no_addr) != ip->i_no_addr) goto out; if (be64_to_cpu(dent->de_inum.no_formal_ino) != ip->i_no_formal_ino) goto out; if (unlikely(IF2DT(ip->i_inode.i_mode) != be16_to_cpu(dent->de_type))) { gfs2_consist_inode(GFS2_I(dir)); ret = -EIO; goto out; } } ret = 0; out: |
c752666c1 [GFS2] Fix bug in... |
1535 |
brelse(bh); |
c752666c1 [GFS2] Fix bug in... |
1536 |
} |
dbb7cae2a [GFS2] Clean up i... |
1537 |
return ret; |
c752666c1 [GFS2] Fix bug in... |
1538 1539 1540 1541 1542 |
} static int dir_new_leaf(struct inode *inode, const struct qstr *name) { struct buffer_head *bh, *obh; |
feaa7bba0 [GFS2] Fix unlink... |
1543 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
1544 |
struct gfs2_leaf *leaf, *oleaf; |
b3b94faa5 [GFS2] The core o... |
1545 |
int error; |
c752666c1 [GFS2] Fix bug in... |
1546 1547 |
u32 index; u64 bn; |
b3b94faa5 [GFS2] The core o... |
1548 |
|
9a0045088 [GFS2] Shrink & r... |
1549 |
index = name->hash >> (32 - ip->i_depth); |
c752666c1 [GFS2] Fix bug in... |
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
error = get_first_leaf(ip, index, &obh); if (error) return error; do { oleaf = (struct gfs2_leaf *)obh->b_data; bn = be64_to_cpu(oleaf->lf_next); if (!bn) break; brelse(obh); error = get_leaf(ip, bn, &obh); if (error) return error; } while(1); |
b3b94faa5 [GFS2] The core o... |
1563 |
|
c752666c1 [GFS2] Fix bug in... |
1564 1565 1566 1567 1568 1569 1570 |
gfs2_trans_add_bh(ip->i_gl, obh, 1); leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth)); if (!leaf) { brelse(obh); return -ENOSPC; } |
4d8012b60 [GFS2] Fix bug wh... |
1571 |
oleaf->lf_next = cpu_to_be64(bh->b_blocknr); |
c752666c1 [GFS2] Fix bug in... |
1572 1573 1574 1575 1576 1577 1578 |
brelse(bh); brelse(obh); error = gfs2_meta_inode_buffer(ip, &bh); if (error) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); |
77658aad2 [GFS2] Eliminate ... |
1579 |
gfs2_add_inode_blocks(&ip->i_inode, 1); |
539e5d6b7 [GFS2] Change arg... |
1580 |
gfs2_dinode_out(ip, bh->b_data); |
c752666c1 [GFS2] Fix bug in... |
1581 1582 |
brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
} /** * gfs2_dir_add - Add new filename into directory * @dip: The GFS2 inode * @filename: The new name * @inode: The inode number of the entry * @type: The type of the entry * * Returns: 0 on success, error code on failure */ |
c752666c1 [GFS2] Fix bug in... |
1594 |
int gfs2_dir_add(struct inode *inode, const struct qstr *name, |
3d6ecb7d1 GFS2: When adding... |
1595 |
const struct gfs2_inode *nip) |
b3b94faa5 [GFS2] The core o... |
1596 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1597 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
1598 1599 1600 |
struct buffer_head *bh; struct gfs2_dirent *dent; struct gfs2_leaf *leaf; |
b3b94faa5 [GFS2] The core o... |
1601 |
int error; |
c752666c1 [GFS2] Fix bug in... |
1602 1603 1604 1605 1606 1607 1608 |
while(1) { dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); if (dent) { if (IS_ERR(dent)) return PTR_ERR(dent); dent = gfs2_init_dirent(inode, dent, name, bh); |
dbb7cae2a [GFS2] Clean up i... |
1609 |
gfs2_inum_out(nip, dent); |
3d6ecb7d1 GFS2: When adding... |
1610 |
dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); |
383f01fbf GFS2: Banish stru... |
1611 |
if (ip->i_diskflags & GFS2_DIF_EXHASH) { |
c752666c1 [GFS2] Fix bug in... |
1612 |
leaf = (struct gfs2_leaf *)bh->b_data; |
bb16b342b [GFS2] be*_add_cp... |
1613 |
be16_add_cpu(&leaf->lf_entries, 1); |
c752666c1 [GFS2] Fix bug in... |
1614 1615 1616 1617 1618 1619 |
} brelse(bh); error = gfs2_meta_inode_buffer(ip, &bh); if (error) break; gfs2_trans_add_bh(ip->i_gl, bh, 1); |
ad6203f2b GFS2: Move "entri... |
1620 |
ip->i_entries++; |
4bd91ba18 [GFS2] Add nanose... |
1621 |
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
3d6ecb7d1 GFS2: When adding... |
1622 1623 |
if (S_ISDIR(nip->i_inode.i_mode)) inc_nlink(&ip->i_inode); |
539e5d6b7 [GFS2] Change arg... |
1624 |
gfs2_dinode_out(ip, bh->b_data); |
c752666c1 [GFS2] Fix bug in... |
1625 1626 1627 1628 |
brelse(bh); error = 0; break; } |
383f01fbf GFS2: Banish stru... |
1629 |
if (!(ip->i_diskflags & GFS2_DIF_EXHASH)) { |
c752666c1 [GFS2] Fix bug in... |
1630 1631 1632 1633 1634 1635 1636 1637 |
error = dir_make_exhash(inode); if (error) break; continue; } error = dir_split_leaf(inode, name); if (error == 0) continue; |
e90deff53 [GFS2] Fix bug in... |
1638 |
if (error < 0) |
c752666c1 [GFS2] Fix bug in... |
1639 |
break; |
9a0045088 [GFS2] Shrink & r... |
1640 |
if (ip->i_depth < GFS2_DIR_MAX_DEPTH) { |
c752666c1 [GFS2] Fix bug in... |
1641 1642 1643 1644 |
error = dir_double_exhash(ip); if (error) break; error = dir_split_leaf(inode, name); |
e90deff53 [GFS2] Fix bug in... |
1645 |
if (error < 0) |
c752666c1 [GFS2] Fix bug in... |
1646 |
break; |
e90deff53 [GFS2] Fix bug in... |
1647 1648 |
if (error == 0) continue; |
c752666c1 [GFS2] Fix bug in... |
1649 1650 1651 1652 1653 1654 1655 |
} error = dir_new_leaf(inode, name); if (!error) continue; error = -ENOSPC; break; } |
b3b94faa5 [GFS2] The core o... |
1656 1657 |
return error; } |
c752666c1 [GFS2] Fix bug in... |
1658 |
|
b3b94faa5 [GFS2] The core o... |
1659 1660 1661 1662 1663 1664 1665 |
/** * gfs2_dir_del - Delete a directory entry * @dip: The GFS2 inode * @filename: The filename * * Returns: 0 on success, error code on failure */ |
855d23ce2 GFS2: Make gfs2_d... |
1666 |
int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) |
b3b94faa5 [GFS2] The core o... |
1667 |
{ |
855d23ce2 GFS2: Make gfs2_d... |
1668 |
const struct qstr *name = &dentry->d_name; |
c752666c1 [GFS2] Fix bug in... |
1669 1670 |
struct gfs2_dirent *dent, *prev = NULL; struct buffer_head *bh; |
b3b94faa5 [GFS2] The core o... |
1671 |
|
c752666c1 [GFS2] Fix bug in... |
1672 1673 |
/* Returns _either_ the entry (if its first in block) or the previous entry otherwise */ |
feaa7bba0 [GFS2] Fix unlink... |
1674 |
dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh); |
c752666c1 [GFS2] Fix bug in... |
1675 1676 1677 1678 1679 1680 1681 1682 1683 |
if (!dent) { gfs2_consist_inode(dip); return -EIO; } if (IS_ERR(dent)) { gfs2_consist_inode(dip); return PTR_ERR(dent); } /* If not first in block, adjust pointers accordingly */ |
71b86f562 [GFS2] Further up... |
1684 |
if (gfs2_dirent_find(dent, name, NULL) == 0) { |
c752666c1 [GFS2] Fix bug in... |
1685 1686 1687 1688 1689 |
prev = dent; dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); } dirent_del(dip, bh, prev, dent); |
383f01fbf GFS2: Banish stru... |
1690 |
if (dip->i_diskflags & GFS2_DIF_EXHASH) { |
c752666c1 [GFS2] Fix bug in... |
1691 1692 1693 1694 1695 |
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; u16 entries = be16_to_cpu(leaf->lf_entries); if (!entries) gfs2_consist_inode(dip); leaf->lf_entries = cpu_to_be16(--entries); |
c752666c1 [GFS2] Fix bug in... |
1696 |
} |
ed3865079 [GFS2] Finally ge... |
1697 |
brelse(bh); |
c752666c1 [GFS2] Fix bug in... |
1698 |
|
ad6203f2b GFS2: Move "entri... |
1699 |
if (!dip->i_entries) |
c752666c1 [GFS2] Fix bug in... |
1700 |
gfs2_consist_inode(dip); |
ad6203f2b GFS2: Move "entri... |
1701 |
dip->i_entries--; |
4bd91ba18 [GFS2] Add nanose... |
1702 |
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; |
855d23ce2 GFS2: Make gfs2_d... |
1703 1704 |
if (S_ISDIR(dentry->d_inode->i_mode)) drop_nlink(&dip->i_inode); |
feaa7bba0 [GFS2] Fix unlink... |
1705 |
mark_inode_dirty(&dip->i_inode); |
b3b94faa5 [GFS2] The core o... |
1706 |
|
ab9bbda02 GFS2: Use ->dirty... |
1707 |
return 0; |
b3b94faa5 [GFS2] The core o... |
1708 |
} |
b3b94faa5 [GFS2] The core o... |
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 |
/** * gfs2_dir_mvino - Change inode number of directory entry * @dip: The GFS2 inode * @filename: * @new_inode: * * This routine changes the inode number of a directory entry. It's used * by rename to change ".." when a directory is moved. * Assumes a glock is held on dvp. * * Returns: errno */ |
c752666c1 [GFS2] Fix bug in... |
1721 |
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, |
dbb7cae2a [GFS2] Clean up i... |
1722 |
const struct gfs2_inode *nip, unsigned int new_type) |
b3b94faa5 [GFS2] The core o... |
1723 |
{ |
c752666c1 [GFS2] Fix bug in... |
1724 1725 |
struct buffer_head *bh; struct gfs2_dirent *dent; |
b3b94faa5 [GFS2] The core o... |
1726 |
int error; |
feaa7bba0 [GFS2] Fix unlink... |
1727 |
dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh); |
c752666c1 [GFS2] Fix bug in... |
1728 1729 1730 1731 1732 1733 |
if (!dent) { gfs2_consist_inode(dip); return -EIO; } if (IS_ERR(dent)) return PTR_ERR(dent); |
b3b94faa5 [GFS2] The core o... |
1734 |
|
c752666c1 [GFS2] Fix bug in... |
1735 |
gfs2_trans_add_bh(dip->i_gl, bh, 1); |
dbb7cae2a [GFS2] Clean up i... |
1736 |
gfs2_inum_out(nip, dent); |
c752666c1 [GFS2] Fix bug in... |
1737 |
dent->de_type = cpu_to_be16(new_type); |
383f01fbf GFS2: Banish stru... |
1738 |
if (dip->i_diskflags & GFS2_DIF_EXHASH) { |
c752666c1 [GFS2] Fix bug in... |
1739 1740 1741 1742 1743 1744 |
brelse(bh); error = gfs2_meta_inode_buffer(dip, &bh); if (error) return error; gfs2_trans_add_bh(dip->i_gl, bh, 1); } |
4bd91ba18 [GFS2] Add nanose... |
1745 |
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; |
539e5d6b7 [GFS2] Change arg... |
1746 |
gfs2_dinode_out(dip, bh->b_data); |
c752666c1 [GFS2] Fix bug in... |
1747 1748 |
brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1749 1750 1751 |
} /** |
b3b94faa5 [GFS2] The core o... |
1752 1753 1754 1755 1756 |
* leaf_dealloc - Deallocate a directory leaf * @dip: the directory * @index: the hash table offset in the directory * @len: the number of pointers to this leaf * @leaf_no: the leaf number |
ec038c826 GFS2: pass leaf_b... |
1757 |
* @leaf_bh: buffer_head for the starting leaf |
d24a7a439 GFS2: Combine tra... |
1758 |
* last_dealloc: 1 if this is the final dealloc for the leaf, else 0 |
b3b94faa5 [GFS2] The core o... |
1759 1760 1761 |
* * Returns: errno */ |
cd915493f [GFS2] Change all... |
1762 |
static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, |
ec038c826 GFS2: pass leaf_b... |
1763 1764 |
u64 leaf_no, struct buffer_head *leaf_bh, int last_dealloc) |
b3b94faa5 [GFS2] The core o... |
1765 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1766 |
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
c752666c1 [GFS2] Fix bug in... |
1767 |
struct gfs2_leaf *tmp_leaf; |
b3b94faa5 [GFS2] The core o... |
1768 1769 |
struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; |
cd915493f [GFS2] Change all... |
1770 |
u64 blk, nblk; |
b3b94faa5 [GFS2] The core o... |
1771 1772 |
unsigned int rg_blocks = 0, l_blocks = 0; char *ht; |
cd915493f [GFS2] Change all... |
1773 |
unsigned int x, size = len * sizeof(u64); |
b3b94faa5 [GFS2] The core o... |
1774 1775 1776 |
int error; memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); |
16c5f06f1 [GFS2] fix GFP_KE... |
1777 |
ht = kzalloc(size, GFP_NOFS); |
b3b94faa5 [GFS2] The core o... |
1778 1779 |
if (!ht) return -ENOMEM; |
564e12b11 GFS2: decouple qu... |
1780 |
if (!gfs2_qadata_get(dip)) { |
182fe5abd [GFS2] possible n... |
1781 1782 1783 |
error = -ENOMEM; goto out; } |
b3b94faa5 [GFS2] The core o... |
1784 1785 1786 |
error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) |
182fe5abd [GFS2] possible n... |
1787 |
goto out_put; |
b3b94faa5 [GFS2] The core o... |
1788 |
|
b3b94faa5 [GFS2] The core o... |
1789 |
/* Count the number of leaves */ |
ec038c826 GFS2: pass leaf_b... |
1790 |
bh = leaf_bh; |
b3b94faa5 [GFS2] The core o... |
1791 |
|
c752666c1 [GFS2] Fix bug in... |
1792 |
for (blk = leaf_no; blk; blk = nblk) { |
ec038c826 GFS2: pass leaf_b... |
1793 1794 1795 1796 1797 |
if (blk != leaf_no) { error = get_leaf(dip, blk, &bh); if (error) goto out_rlist; } |
c752666c1 [GFS2] Fix bug in... |
1798 1799 |
tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); |
ec038c826 GFS2: pass leaf_b... |
1800 1801 |
if (blk != leaf_no) brelse(bh); |
b3b94faa5 [GFS2] The core o... |
1802 |
|
70b0c3656 GFS2: Use cached ... |
1803 |
gfs2_rlist_add(dip, &rlist, blk); |
b3b94faa5 [GFS2] The core o... |
1804 1805 |
l_blocks++; } |
fe6c991c5 [GFS2] Get rid of... |
1806 |
gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); |
b3b94faa5 [GFS2] The core o... |
1807 1808 1809 |
for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; |
5c676f6d3 [GFS2] Macros rem... |
1810 |
rgd = rlist.rl_ghs[x].gh_gl->gl_object; |
bb8d8a6f5 [GFS2] Fix sign p... |
1811 |
rg_blocks += rgd->rd_length; |
b3b94faa5 [GFS2] The core o... |
1812 1813 1814 1815 1816 1817 1818 |
} error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); if (error) goto out_rlist; error = gfs2_trans_begin(sdp, |
5c676f6d3 [GFS2] Macros rem... |
1819 |
rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) + |
b3b94faa5 [GFS2] The core o... |
1820 1821 1822 |
RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks); if (error) goto out_rg_gunlock; |
ec038c826 GFS2: pass leaf_b... |
1823 |
bh = leaf_bh; |
c752666c1 [GFS2] Fix bug in... |
1824 |
for (blk = leaf_no; blk; blk = nblk) { |
ec038c826 GFS2: pass leaf_b... |
1825 1826 1827 1828 1829 |
if (blk != leaf_no) { error = get_leaf(dip, blk, &bh); if (error) goto out_end_trans; } |
c752666c1 [GFS2] Fix bug in... |
1830 1831 |
tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); |
ec038c826 GFS2: pass leaf_b... |
1832 1833 |
if (blk != leaf_no) brelse(bh); |
b3b94faa5 [GFS2] The core o... |
1834 1835 |
gfs2_free_meta(dip, blk, 1); |
77658aad2 [GFS2] Eliminate ... |
1836 |
gfs2_add_inode_blocks(&dip->i_inode, -1); |
b3b94faa5 [GFS2] The core o... |
1837 |
} |
cd915493f [GFS2] Change all... |
1838 |
error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); |
b3b94faa5 [GFS2] The core o... |
1839 1840 1841 1842 1843 1844 1845 1846 1847 |
if (error != size) { if (error >= 0) error = -EIO; goto out_end_trans; } error = gfs2_meta_inode_buffer(dip, &dibh); if (error) goto out_end_trans; |
d4e9c4c3b [GFS2] Add an add... |
1848 |
gfs2_trans_add_bh(dip->i_gl, dibh, 1); |
d24a7a439 GFS2: Combine tra... |
1849 1850 1851 1852 |
/* On the last dealloc, make this a regular file in case we crash. (We don't want to free these blocks a second time.) */ if (last_dealloc) dip->i_inode.i_mode = S_IFREG; |
539e5d6b7 [GFS2] Change arg... |
1853 |
gfs2_dinode_out(dip, dibh->b_data); |
b3b94faa5 [GFS2] The core o... |
1854 |
brelse(dibh); |
a91ea69ff [GFS2] Align all ... |
1855 |
out_end_trans: |
b3b94faa5 [GFS2] The core o... |
1856 |
gfs2_trans_end(sdp); |
a91ea69ff [GFS2] Align all ... |
1857 |
out_rg_gunlock: |
b3b94faa5 [GFS2] The core o... |
1858 |
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); |
a91ea69ff [GFS2] Align all ... |
1859 |
out_rlist: |
b3b94faa5 [GFS2] The core o... |
1860 |
gfs2_rlist_free(&rlist); |
b3b94faa5 [GFS2] The core o... |
1861 |
gfs2_quota_unhold(dip); |
182fe5abd [GFS2] possible n... |
1862 |
out_put: |
564e12b11 GFS2: decouple qu... |
1863 |
gfs2_qadata_put(dip); |
182fe5abd [GFS2] possible n... |
1864 |
out: |
b3b94faa5 [GFS2] The core o... |
1865 |
kfree(ht); |
b3b94faa5 [GFS2] The core o... |
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 |
return error; } /** * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory * @dip: the directory * * Dealloc all on-disk directory leaves to FREEMETA state * Change on-disk inode type to "regular file" * * Returns: errno */ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) { |
556bb1799 GFS2: move functi... |
1881 1882 1883 |
struct buffer_head *bh; struct gfs2_leaf *leaf; u32 hsize, len; |
556bb1799 GFS2: move functi... |
1884 1885 1886 1887 1888 1889 |
u32 index = 0, next_index; __be64 *lp; u64 leaf_no; int error = 0, last; hsize = 1 << dip->i_depth; |
556bb1799 GFS2: move functi... |
1890 |
|
17d539f04 GFS2: Cache dir h... |
1891 1892 1893 |
lp = gfs2_dir_get_hash_table(dip); if (IS_ERR(lp)) return PTR_ERR(lp); |
556bb1799 GFS2: move functi... |
1894 1895 |
while (index < hsize) { |
17d539f04 GFS2: Cache dir h... |
1896 |
leaf_no = be64_to_cpu(lp[index]); |
556bb1799 GFS2: move functi... |
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 |
if (leaf_no) { error = get_leaf(dip, leaf_no, &bh); if (error) goto out; leaf = (struct gfs2_leaf *)bh->b_data; len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); next_index = (index & ~(len - 1)) + len; last = ((next_index >= hsize) ? 1 : 0); error = leaf_dealloc(dip, index, len, leaf_no, bh, last); brelse(bh); if (error) goto out; index = next_index; } else index++; } if (index != hsize) { gfs2_consist_inode(dip); error = -EIO; } out: |
556bb1799 GFS2: move functi... |
1922 1923 |
return error; |
b3b94faa5 [GFS2] The core o... |
1924 1925 1926 1927 1928 1929 |
} /** * gfs2_diradd_alloc_required - find if adding entry will require an allocation * @ip: the file being written to * @filname: the filename that's going to be added |
b3b94faa5 [GFS2] The core o... |
1930 |
* |
c752666c1 [GFS2] Fix bug in... |
1931 |
* Returns: 1 if alloc required, 0 if not, -ve on error |
b3b94faa5 [GFS2] The core o... |
1932 |
*/ |
4d8012b60 [GFS2] Fix bug wh... |
1933 |
int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
1934 |
{ |
c752666c1 [GFS2] Fix bug in... |
1935 1936 |
struct gfs2_dirent *dent; struct buffer_head *bh; |
b3b94faa5 [GFS2] The core o... |
1937 |
|
c752666c1 [GFS2] Fix bug in... |
1938 |
dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); |
ed3865079 [GFS2] Finally ge... |
1939 |
if (!dent) { |
c752666c1 [GFS2] Fix bug in... |
1940 |
return 1; |
ed3865079 [GFS2] Finally ge... |
1941 |
} |
c752666c1 [GFS2] Fix bug in... |
1942 1943 1944 1945 |
if (IS_ERR(dent)) return PTR_ERR(dent); brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1946 |
} |