Blame view
fs/gfs2/dir.c
45.8 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
* 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 * * dip->i_di.di_flags & GFS2_DIF_EXHASH is true * * 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 56 57 58 |
#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> |
b3b94faa5 [GFS2] The core o... |
59 60 |
#include <linux/buffer_head.h> #include <linux/sort.h> |
5c676f6d3 [GFS2] Macros rem... |
61 |
#include <linux/gfs2_ondisk.h> |
71b86f562 [GFS2] Further up... |
62 |
#include <linux/crc32.h> |
fe1bdedc6 [GFS2] Use vmallo... |
63 |
#include <linux/vmalloc.h> |
7d308590a [GFS2] Export lm_... |
64 |
#include <linux/lm_interface.h> |
b3b94faa5 [GFS2] The core o... |
65 66 |
#include "gfs2.h" |
5c676f6d3 [GFS2] Macros rem... |
67 |
#include "incore.h" |
b3b94faa5 [GFS2] The core o... |
68 69 70 |
#include "dir.h" #include "glock.h" #include "inode.h" |
b3b94faa5 [GFS2] The core o... |
71 72 73 74 |
#include "meta_io.h" #include "quota.h" #include "rgrp.h" #include "trans.h" |
e13940ba5 [GFS2] Make dir.c... |
75 |
#include "bmap.h" |
5c676f6d3 [GFS2] Macros rem... |
76 |
#include "util.h" |
b3b94faa5 [GFS2] The core o... |
77 78 79 |
#define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ |
cd915493f [GFS2] Change all... |
80 81 |
#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) |
b3b94faa5 [GFS2] The core o... |
82 |
|
907b9bceb [GFS2/DLM] Fix tr... |
83 |
typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, |
2bdbc5d73 [GFS2] Directory ... |
84 85 86 |
u64 leaf_no, void *data); typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); |
b3b94faa5 [GFS2] The core o... |
87 |
|
61e085a88 [GFS2] Tidy up di... |
88 |
|
cd915493f [GFS2] Change all... |
89 |
int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, |
61e085a88 [GFS2] Tidy up di... |
90 |
struct buffer_head **bhp) |
e13940ba5 [GFS2] Make dir.c... |
91 92 |
{ struct buffer_head *bh; |
e13940ba5 [GFS2] Make dir.c... |
93 |
|
61e085a88 [GFS2] Tidy up di... |
94 95 96 97 |
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... |
98 99 100 |
*bhp = bh; return 0; } |
cd915493f [GFS2] Change all... |
101 |
static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, |
61e085a88 [GFS2] Tidy up di... |
102 103 104 105 |
struct buffer_head **bhp) { struct buffer_head *bh; int error; |
e13940ba5 [GFS2] Make dir.c... |
106 |
|
7276b3b0c [GFS2] Tidy up me... |
107 |
error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); |
61e085a88 [GFS2] Tidy up di... |
108 109 |
if (error) return error; |
feaa7bba0 [GFS2] Fix unlink... |
110 |
if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { |
61e085a88 [GFS2] Tidy up di... |
111 112 113 114 115 116 |
brelse(bh); return -EIO; } *bhp = bh; return 0; } |
e13940ba5 [GFS2] Make dir.c... |
117 118 119 |
static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, unsigned int offset, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
120 121 122 123 124 125 126 127 128 |
{ 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... |
129 |
memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); |
e13940ba5 [GFS2] Make dir.c... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
if (ip->i_di.di_size < offset + size) ip->i_di.di_size = offset + size; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); gfs2_dinode_out(&ip->i_di, dibh->b_data); 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... |
152 |
u64 offset, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
153 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
154 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
e13940ba5 [GFS2] Make dir.c... |
155 |
struct buffer_head *dibh; |
cd915493f [GFS2] Change all... |
156 157 |
u64 lblock, dblock; u32 extlen = 0; |
e13940ba5 [GFS2] Make dir.c... |
158 159 160 161 162 163 164 165 166 |
unsigned int o; int copied = 0; int error = 0; if (!size) return 0; if (gfs2_is_stuffed(ip) && offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) |
568f4c965 [GFS2] 80 Column ... |
167 168 |
return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset, size); |
e13940ba5 [GFS2] Make dir.c... |
169 170 171 172 173 |
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; if (gfs2_is_stuffed(ip)) { |
f25ef0c1b [GFS2] Tidy gfs2_... |
174 |
error = gfs2_unstuff_dinode(ip, NULL); |
e13940ba5 [GFS2] Make dir.c... |
175 |
if (error) |
c752666c1 [GFS2] Fix bug in... |
176 |
return error; |
e13940ba5 [GFS2] Make dir.c... |
177 178 179 180 181 182 183 184 |
} lblock = offset; o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); while (copied < size) { unsigned int amount; struct buffer_head *bh; |
348acd48f [GFS2] fs/gfs2/di... |
185 |
int new = 0; |
e13940ba5 [GFS2] Make dir.c... |
186 187 188 189 190 191 192 |
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... |
193 |
error = gfs2_extent_map(&ip->i_inode, lblock, &new, |
fd88de569 [GFS2] Readpages ... |
194 |
&dblock, &extlen); |
e13940ba5 [GFS2] Make dir.c... |
195 196 197 198 199 200 |
if (error) goto fail; error = -EIO; if (gfs2_assert_withdraw(sdp, dblock)) goto fail; } |
61e085a88 [GFS2] Tidy up di... |
201 202 203 204 |
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... |
205 206 207 208 209 210 |
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... |
211 |
|
899bb2645 [GFS2] Fix bug in... |
212 |
buf += amount; |
e13940ba5 [GFS2] Make dir.c... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
copied += amount; lblock++; dblock++; extlen--; o = sizeof(struct gfs2_meta_header); } out: error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; if (ip->i_di.di_size < offset + copied) ip->i_di.di_size = offset + copied; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); return copied; fail: if (copied) goto out; return error; } static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, |
7276b3b0c [GFS2] Tidy up me... |
242 |
u64 offset, unsigned int size) |
e13940ba5 [GFS2] Make dir.c... |
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
{ struct buffer_head *dibh; int error; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { offset += sizeof(struct gfs2_dinode); memcpy(buf, dibh->b_data + offset, size); 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 * @offset: File offset to begin jdata_readng from * @size: Amount of data to transfer * * Returns: The amount of data actually copied or the error */ |
7276b3b0c [GFS2] Tidy up me... |
267 268 |
static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, unsigned int size, unsigned ra) |
e13940ba5 [GFS2] Make dir.c... |
269 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
270 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
cd915493f [GFS2] Change all... |
271 272 |
u64 lblock, dblock; u32 extlen = 0; |
e13940ba5 [GFS2] Make dir.c... |
273 274 275 276 277 278 |
unsigned int o; int copied = 0; int error = 0; if (offset >= ip->i_di.di_size) return 0; |
c53921248 [GFS2] More style... |
279 |
if (offset + size > ip->i_di.di_size) |
e13940ba5 [GFS2] Make dir.c... |
280 281 282 283 284 285 |
size = ip->i_di.di_size - offset; if (!size) return 0; if (gfs2_is_stuffed(ip)) |
7276b3b0c [GFS2] Tidy up me... |
286 |
return gfs2_dir_read_stuffed(ip, buf, offset, size); |
e13940ba5 [GFS2] Make dir.c... |
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; lblock = offset; 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... |
305 |
error = gfs2_extent_map(&ip->i_inode, lblock, &new, |
fd88de569 [GFS2] Readpages ... |
306 |
&dblock, &extlen); |
7276b3b0c [GFS2] Tidy up me... |
307 |
if (error || !dblock) |
e13940ba5 [GFS2] Make dir.c... |
308 |
goto fail; |
7276b3b0c [GFS2] Tidy up me... |
309 310 311 312 |
BUG_ON(extlen < 1); if (!ra) extlen = 1; bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); |
b7d8ac3e1 [GFS2] gfs2_dir_r... |
313 |
} else { |
7276b3b0c [GFS2] Tidy up me... |
314 |
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); |
e13940ba5 [GFS2] Make dir.c... |
315 316 |
if (error) goto fail; |
7276b3b0c [GFS2] Tidy up me... |
317 318 319 320 321 322 323 324 |
} error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD); if (error) { brelse(bh); goto fail; } dblock++; extlen--; |
e13940ba5 [GFS2] Make dir.c... |
325 326 |
memcpy(buf, bh->b_data + o, amount); brelse(bh); |
899bb2645 [GFS2] Fix bug in... |
327 |
buf += amount; |
e13940ba5 [GFS2] Make dir.c... |
328 329 |
copied += amount; lblock++; |
e13940ba5 [GFS2] Make dir.c... |
330 331 332 333 334 335 336 |
o = sizeof(struct gfs2_meta_header); } return copied; fail: return (copied) ? copied : error; } |
c752666c1 [GFS2] Fix bug in... |
337 338 339 340 341 342 |
static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, const struct qstr *name, int ret) { if (dent->de_inum.no_addr != 0 && be32_to_cpu(dent->de_hash) == name->hash && be16_to_cpu(dent->de_name_len) == name->len && |
2bdbc5d73 [GFS2] Directory ... |
343 |
memcmp(dent+1, name->name, name->len) == 0) |
c752666c1 [GFS2] Fix bug in... |
344 345 346 347 348 |
return ret; return 0; } static int gfs2_dirent_find(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
349 350 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
351 352 353 354 355 |
{ return __gfs2_dirent_find(dent, name, 1); } static int gfs2_dirent_prev(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
356 357 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
358 359 360 361 362 363 364 |
{ 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... |
365 |
*/ |
c752666c1 [GFS2] Fix bug in... |
366 |
static int gfs2_dirent_last(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
367 368 |
const struct qstr *name, void *opaque) |
c752666c1 [GFS2] Fix bug in... |
369 370 371 372 373 374 375 |
{ 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... |
376 |
|
c752666c1 [GFS2] Fix bug in... |
377 |
static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, |
71b86f562 [GFS2] Further up... |
378 379 |
const struct qstr *name, void *opaque) |
b3b94faa5 [GFS2] The core o... |
380 |
{ |
c752666c1 [GFS2] Fix bug in... |
381 382 383 |
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); |
71b86f562 [GFS2] Further up... |
384 385 |
if (!dent->de_inum.no_addr) actual = GFS2_DIRENT_SIZE(0); |
c53921248 [GFS2] More style... |
386 |
if (totlen - actual >= required) |
c752666c1 [GFS2] Fix bug in... |
387 388 389 |
return 1; return 0; } |
71b86f562 [GFS2] Further up... |
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
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; if (dent->de_inum.no_addr) { g->pdent[g->offset++] = dent; } return 0; } |
c752666c1 [GFS2] Fix bug in... |
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
/* * 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"; if (unlikely(!first && !dent->de_inum.no_addr)) goto error; msg = "name length is greater than space in dirent"; if (dent->de_inum.no_addr && 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... |
440 |
} |
71b86f562 [GFS2] Further up... |
441 |
static int gfs2_dirent_offset(const void *buf) |
c752666c1 [GFS2] Fix bug in... |
442 |
{ |
71b86f562 [GFS2] Further up... |
443 444 |
const struct gfs2_meta_header *h = buf; int offset; |
c752666c1 [GFS2] Fix bug in... |
445 446 |
BUG_ON(buf == NULL); |
c752666c1 [GFS2] Fix bug in... |
447 |
|
e3167ded1 [GFS] Fix bug in ... |
448 |
switch(be32_to_cpu(h->mh_type)) { |
c752666c1 [GFS2] Fix bug in... |
449 450 451 452 453 454 455 456 457 |
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... |
458 459 460 461 |
return offset; wrong_type: printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u ", |
e3167ded1 [GFS] Fix bug in ... |
462 |
be32_to_cpu(h->mh_type)); |
71b86f562 [GFS2] Further up... |
463 464 |
return -1; } |
2bdbc5d73 [GFS2] Directory ... |
465 |
static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, |
71b86f562 [GFS2] Further up... |
466 467 468 469 470 471 472 473 |
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... |
474 |
|
71b86f562 [GFS2] Further up... |
475 476 477 478 479 |
ret = gfs2_dirent_offset(buf); if (ret < 0) goto consist_inode; offset = ret; |
c752666c1 [GFS2] Fix bug in... |
480 |
prev = NULL; |
2bdbc5d73 [GFS2] Directory ... |
481 |
dent = buf + offset; |
c752666c1 [GFS2] Fix bug in... |
482 483 484 485 |
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... |
486 |
ret = scan(dent, name, opaque); |
c752666c1 [GFS2] Fix bug in... |
487 488 489 490 491 492 |
if (ret) break; offset += size; if (offset == len) break; prev = dent; |
2bdbc5d73 [GFS2] Directory ... |
493 |
dent = buf + offset; |
c752666c1 [GFS2] Fix bug in... |
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
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... |
510 |
consist_inode: |
feaa7bba0 [GFS2] Fix unlink... |
511 |
gfs2_consist_inode(GFS2_I(inode)); |
c752666c1 [GFS2] Fix bug in... |
512 513 |
return ERR_PTR(-EIO); } |
b3b94faa5 [GFS2] The core o... |
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
/** * dirent_first - Return the first dirent * @dip: the directory * @bh: The buffer * @dent: Pointer to list of dirents * * return first dirent whether bh points to leaf or stuffed dinode * * Returns: IS_LEAF, IS_DINODE, or -errno */ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent **dent) { struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data; |
e3167ded1 [GFS] Fix bug in ... |
529 |
if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { |
feaa7bba0 [GFS2] Fix unlink... |
530 |
if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh)) |
b3b94faa5 [GFS2] The core o... |
531 532 533 534 535 |
return -EIO; *dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf)); return IS_LEAF; } else { |
feaa7bba0 [GFS2] Fix unlink... |
536 |
if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI)) |
b3b94faa5 [GFS2] The core o... |
537 538 539 540 541 542 |
return -EIO; *dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode)); return IS_DINODE; } } |
2bdbc5d73 [GFS2] Directory ... |
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
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... |
560 561 562 563 564 565 566 567 568 569 570 571 |
/** * 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 ... |
572 573 574 |
struct gfs2_dirent *cur = *dent, *tmp; char *bh_end = bh->b_data + bh->b_size; int ret; |
b3b94faa5 [GFS2] The core o... |
575 |
|
2bdbc5d73 [GFS2] Directory ... |
576 577 578 |
ret = dirent_check_reclen(dip, cur, bh_end); if (ret < 0) return ret; |
4dd651adb [GFS2] Fix the bu... |
579 |
|
2bdbc5d73 [GFS2] Directory ... |
580 581 582 583 |
tmp = (void *)cur + ret; ret = dirent_check_reclen(dip, tmp, bh_end); if (ret == -EIO) return ret; |
4dd651adb [GFS2] Fix the bu... |
584 |
|
b3b94faa5 [GFS2] The core o... |
585 586 587 588 589 590 591 |
/* Only the first dent could ever have de_inum.no_addr == 0 */ if (!tmp->de_inum.no_addr) { gfs2_consist_inode(dip); return -EIO; } *dent = tmp; |
b3b94faa5 [GFS2] The core o... |
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
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... |
607 |
u16 cur_rec_len, prev_rec_len; |
b3b94faa5 [GFS2] The core o... |
608 609 610 611 612 |
if (!cur->de_inum.no_addr) { gfs2_consist_inode(dip); return; } |
d4e9c4c3b [GFS2] Add an add... |
613 |
gfs2_trans_add_bh(dip->i_gl, bh, 1); |
b3b94faa5 [GFS2] The core o... |
614 615 616 617 618 619 620 621 622 623 624 |
/* 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) { cur->de_inum.no_addr = 0; /* No endianess worries */ return; } /* Combine this dentry with the previous one. */ |
fc69d0d33 [GFS2] Change ond... |
625 626 |
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... |
627 628 629 630 631 632 633 |
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... |
634 |
prev->de_rec_len = cpu_to_be16(prev_rec_len); |
b3b94faa5 [GFS2] The core o... |
635 |
} |
c752666c1 [GFS2] Fix bug in... |
636 637 638 |
/* * Takes a dent from which to grab space as an argument. Returns the * newly created dent. |
b3b94faa5 [GFS2] The core o... |
639 |
*/ |
08bc2dbc7 [GFS2] [-mm patch... |
640 641 642 643 |
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... |
644 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
645 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
646 647 648 649 650 651 652 653 654 655 656 657 |
struct gfs2_dirent *ndent; unsigned offset = 0, totlen; if (dent->de_inum.no_addr) 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... |
658 |
} |
c752666c1 [GFS2] Fix bug in... |
659 660 661 |
static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, struct buffer_head *bh, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
662 663 |
{ struct gfs2_dirent *dent; |
907b9bceb [GFS2/DLM] Fix tr... |
664 |
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
71b86f562 [GFS2] Further up... |
665 |
gfs2_dirent_find_space, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
666 667 668 |
if (!dent || IS_ERR(dent)) return dent; return gfs2_init_dirent(inode, dent, name, bh); |
b3b94faa5 [GFS2] The core o... |
669 |
} |
cd915493f [GFS2] Change all... |
670 |
static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, |
b3b94faa5 [GFS2] The core o... |
671 672 673 |
struct buffer_head **bhp) { int error; |
7276b3b0c [GFS2] Tidy up me... |
674 |
error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); |
feaa7bba0 [GFS2] Fix unlink... |
675 676 677 |
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... |
678 |
error = -EIO; |
feaa7bba0 [GFS2] Fix unlink... |
679 |
} |
b3b94faa5 [GFS2] The core o... |
680 681 682 683 684 685 686 687 688 689 690 691 |
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... |
692 693 |
static int get_leaf_nr(struct gfs2_inode *dip, u32 index, u64 *leaf_out) |
b3b94faa5 [GFS2] The core o... |
694 |
{ |
b44b84d76 [GFS2] gfs2 misc ... |
695 |
__be64 leaf_no; |
b3b94faa5 [GFS2] The core o... |
696 |
int error; |
e13940ba5 [GFS2] Make dir.c... |
697 |
error = gfs2_dir_read_data(dip, (char *)&leaf_no, |
b44b84d76 [GFS2] gfs2 misc ... |
698 699 |
index * sizeof(__be64), sizeof(__be64), 0); |
cd915493f [GFS2] Change all... |
700 |
if (error != sizeof(u64)) |
b3b94faa5 [GFS2] The core o... |
701 702 703 704 705 706 |
return (error < 0) ? error : -EIO; *leaf_out = be64_to_cpu(leaf_no); return 0; } |
cd915493f [GFS2] Change all... |
707 |
static int get_first_leaf(struct gfs2_inode *dip, u32 index, |
b3b94faa5 [GFS2] The core o... |
708 709 |
struct buffer_head **bh_out) { |
cd915493f [GFS2] Change all... |
710 |
u64 leaf_no; |
b3b94faa5 [GFS2] The core o... |
711 712 713 714 715 716 717 718 |
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... |
719 720 721 722 |
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... |
723 |
{ |
c752666c1 [GFS2] Fix bug in... |
724 725 |
struct buffer_head *bh; struct gfs2_dirent *dent; |
feaa7bba0 [GFS2] Fix unlink... |
726 |
struct gfs2_inode *ip = GFS2_I(inode); |
b3b94faa5 [GFS2] The core o... |
727 |
int error; |
c752666c1 [GFS2] Fix bug in... |
728 729 730 731 732 733 734 735 736 |
if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { struct gfs2_leaf *leaf; unsigned hsize = 1 << ip->i_di.di_depth; unsigned index; u64 ln; if (hsize * sizeof(u64) != ip->i_di.di_size) { gfs2_consist_inode(ip); return ERR_PTR(-EIO); } |
907b9bceb [GFS2/DLM] Fix tr... |
737 |
|
c752666c1 [GFS2] Fix bug in... |
738 739 740 741 742 743 |
index = name->hash >> (32 - ip->i_di.di_depth); 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... |
744 |
scan, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
745 746 747 748 |
if (dent) goto got_dent; leaf = (struct gfs2_leaf *)bh->b_data; ln = be64_to_cpu(leaf->lf_next); |
f4154ea03 [GFS2] Update jou... |
749 |
brelse(bh); |
c752666c1 [GFS2] Fix bug in... |
750 751 |
if (!ln) break; |
907b9bceb [GFS2/DLM] Fix tr... |
752 |
|
c752666c1 [GFS2] Fix bug in... |
753 754 |
error = get_leaf(ip, ln, &bh); } while(!error); |
b3b94faa5 [GFS2] The core o... |
755 |
|
c752666c1 [GFS2] Fix bug in... |
756 |
return error ? ERR_PTR(error) : NULL; |
b3b94faa5 [GFS2] The core o... |
757 |
} |
b3b94faa5 [GFS2] The core o... |
758 |
|
907b9bceb [GFS2/DLM] Fix tr... |
759 |
|
c752666c1 [GFS2] Fix bug in... |
760 761 762 |
error = gfs2_meta_inode_buffer(ip, &bh); if (error) return ERR_PTR(error); |
71b86f562 [GFS2] Further up... |
763 |
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); |
c752666c1 [GFS2] Fix bug in... |
764 |
got_dent: |
f4154ea03 [GFS2] Update jou... |
765 |
if (unlikely(dent == NULL || IS_ERR(dent))) { |
ed3865079 [GFS2] Finally ge... |
766 767 768 |
brelse(bh); bh = NULL; } |
c752666c1 [GFS2] Fix bug in... |
769 770 771 |
*pbh = bh; return dent; } |
b3b94faa5 [GFS2] The core o... |
772 |
|
c752666c1 [GFS2] Fix bug in... |
773 774 |
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { |
feaa7bba0 [GFS2] Fix unlink... |
775 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
776 777 778 779 |
u64 bn = gfs2_alloc_meta(ip); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; struct gfs2_dirent *dent; |
71b86f562 [GFS2] Further up... |
780 |
struct qstr name = { .name = "", .len = 0, .hash = 0 }; |
c752666c1 [GFS2] Fix bug in... |
781 782 |
if (!bh) return NULL; |
907b9bceb [GFS2/DLM] Fix tr... |
783 |
|
c752666c1 [GFS2] Fix bug in... |
784 785 786 787 |
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 ... |
788 |
leaf->lf_entries = 0; |
a2d7d021d [GFS2] gfs2 endia... |
789 |
leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); |
2bdbc5d73 [GFS2] Directory ... |
790 |
leaf->lf_next = 0; |
c752666c1 [GFS2] Fix bug in... |
791 792 |
memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); dent = (struct gfs2_dirent *)(leaf+1); |
71b86f562 [GFS2] Further up... |
793 |
gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); |
c752666c1 [GFS2] Fix bug in... |
794 795 |
*pbh = bh; return leaf; |
b3b94faa5 [GFS2] The core o... |
796 797 798 799 800 801 802 803 |
} /** * 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... |
804 |
static int dir_make_exhash(struct inode *inode) |
b3b94faa5 [GFS2] The core o... |
805 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
806 807 |
struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); |
b3b94faa5 [GFS2] The core o... |
808 |
struct gfs2_dirent *dent; |
c752666c1 [GFS2] Fix bug in... |
809 |
struct qstr args; |
b3b94faa5 [GFS2] The core o... |
810 811 812 |
struct buffer_head *bh, *dibh; struct gfs2_leaf *leaf; int y; |
cd915493f [GFS2] Change all... |
813 |
u32 x; |
b44b84d76 [GFS2] gfs2 misc ... |
814 815 |
__be64 *lp; u64 bn; |
b3b94faa5 [GFS2] The core o... |
816 817 818 819 820 |
int error; error = gfs2_meta_inode_buffer(dip, &dibh); if (error) return error; |
b3b94faa5 [GFS2] The core o... |
821 |
/* Turn over a new leaf */ |
c752666c1 [GFS2] Fix bug in... |
822 823 824 825 |
leaf = new_leaf(inode, &bh, 0); if (!leaf) return -ENOSPC; bn = bh->b_blocknr; |
b3b94faa5 [GFS2] The core o... |
826 827 |
gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16)); |
b3b94faa5 [GFS2] The core o... |
828 829 830 831 832 833 834 835 836 837 |
leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries); /* 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... |
838 839 840 |
args.len = bh->b_size - sizeof(struct gfs2_dinode) + sizeof(struct gfs2_leaf); args.name = bh->b_data; |
feaa7bba0 [GFS2] Fix unlink... |
841 |
dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size, |
71b86f562 [GFS2] Further up... |
842 |
gfs2_dirent_last, &args, NULL); |
c752666c1 [GFS2] Fix bug in... |
843 844 845 846 847 848 849 850 851 |
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... |
852 |
} |
b3b94faa5 [GFS2] The core o... |
853 854 855 |
/* Adjust the last dirent's record length (Remember that dent still points to the last entry.) */ |
4dd651adb [GFS2] Fix the bu... |
856 |
dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) + |
b3b94faa5 [GFS2] The core o... |
857 |
sizeof(struct gfs2_dinode) - |
4dd651adb [GFS2] Fix the bu... |
858 |
sizeof(struct gfs2_leaf)); |
b3b94faa5 [GFS2] The core o... |
859 860 861 862 863 |
brelse(bh); /* We're done with the new leaf block, now setup the new hash table. */ |
d4e9c4c3b [GFS2] Add an add... |
864 |
gfs2_trans_add_bh(dip->i_gl, dibh, 1); |
b3b94faa5 [GFS2] The core o... |
865 |
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
b44b84d76 [GFS2] gfs2 misc ... |
866 |
lp = (__be64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); |
b3b94faa5 [GFS2] The core o... |
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 |
for (x = sdp->sd_hash_ptrs; x--; lp++) *lp = cpu_to_be64(bn); dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; dip->i_di.di_blocks++; dip->i_di.di_flags |= GFS2_DIF_EXHASH; dip->i_di.di_payload_format = 0; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; dip->i_di.di_depth = y; gfs2_dinode_out(&dip->i_di, dibh->b_data); 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... |
894 |
static int dir_split_leaf(struct inode *inode, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
895 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
896 |
struct gfs2_inode *dip = GFS2_I(inode); |
b3b94faa5 [GFS2] The core o... |
897 898 |
struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; |
4da3c6463 [GFS2] Fix a coup... |
899 |
struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new; |
cd915493f [GFS2] Change all... |
900 |
u32 start, len, half_len, divider; |
b44b84d76 [GFS2] gfs2 misc ... |
901 902 |
u64 bn, leaf_no; __be64 *lp; |
cd915493f [GFS2] Change all... |
903 |
u32 index; |
b3b94faa5 [GFS2] The core o... |
904 905 |
int x, moved = 0; int error; |
c752666c1 [GFS2] Fix bug in... |
906 907 908 909 |
index = name->hash >> (32 - dip->i_di.di_depth); error = get_leaf_nr(dip, index, &leaf_no); if (error) return error; |
b3b94faa5 [GFS2] The core o... |
910 911 |
/* Get the old leaf block */ |
b3b94faa5 [GFS2] The core o... |
912 913 |
error = get_leaf(dip, leaf_no, &obh); if (error) |
e90deff53 [GFS2] Fix bug in... |
914 |
return error; |
b3b94faa5 [GFS2] The core o... |
915 |
|
b3b94faa5 [GFS2] The core o... |
916 |
oleaf = (struct gfs2_leaf *)obh->b_data; |
e90deff53 [GFS2] Fix bug in... |
917 918 919 920 921 922 |
if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) { brelse(obh); return 1; /* can't split */ } gfs2_trans_add_bh(dip->i_gl, obh, 1); |
b3b94faa5 [GFS2] The core o... |
923 |
|
c752666c1 [GFS2] Fix bug in... |
924 925 926 927 928 929 |
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... |
930 |
|
c752666c1 [GFS2] Fix bug in... |
931 |
/* Compute the start and len of leaf pointers in the hash table. */ |
b3b94faa5 [GFS2] The core o... |
932 933 934 |
len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { |
e90deff53 [GFS2] Fix bug in... |
935 936 |
printk(KERN_WARNING "di_depth %u lf_depth %u index %u ", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index); |
b3b94faa5 [GFS2] The core o... |
937 938 939 940 941 942 943 944 945 946 |
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. */ |
b44b84d76 [GFS2] gfs2 misc ... |
947 |
lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS | __GFP_NOFAIL); |
b3b94faa5 [GFS2] The core o... |
948 |
/* Change the pointers */ |
b3b94faa5 [GFS2] The core o... |
949 950 |
for (x = 0; x < half_len; x++) lp[x] = cpu_to_be64(bn); |
cd915493f [GFS2] Change all... |
951 952 953 |
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... |
954 955 956 957 958 959 960 961 |
if (error >= 0) error = -EIO; goto fail_lpfree; } kfree(lp); /* Compute the divider */ |
b3b94faa5 [GFS2] The core o... |
962 963 964 |
divider = (start + half_len) << (32 - dip->i_di.di_depth); /* Copy the entries */ |
b3b94faa5 [GFS2] The core o... |
965 966 967 968 969 970 971 972 973 |
dirent_first(dip, obh, &dent); do { next = dent; if (dirent_next(dip, obh, &next)) next = NULL; if (dent->de_inum.no_addr && be32_to_cpu(dent->de_hash) < divider) { |
c752666c1 [GFS2] Fix bug in... |
974 975 976 977 |
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... |
978 |
new = gfs2_dirent_alloc(inode, nbh, &str); |
c752666c1 [GFS2] Fix bug in... |
979 980 981 982 |
if (IS_ERR(new)) { error = PTR_ERR(new); break; } |
b3b94faa5 [GFS2] The core o... |
983 984 |
new->de_inum = dent->de_inum; /* No endian worries */ |
b3b94faa5 [GFS2] The core o... |
985 |
new->de_type = dent->de_type; /* No endian worries */ |
c752666c1 [GFS2] Fix bug in... |
986 |
nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1); |
b3b94faa5 [GFS2] The core o... |
987 988 989 990 991 |
dirent_del(dip, obh, prev, dent); if (!oleaf->lf_entries) gfs2_consist_inode(dip); |
c752666c1 [GFS2] Fix bug in... |
992 |
oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1); |
b3b94faa5 [GFS2] The core o... |
993 994 995 996 997 |
if (!prev) prev = dent; moved = 1; |
c752666c1 [GFS2] Fix bug in... |
998 |
} else { |
b3b94faa5 [GFS2] The core o... |
999 |
prev = dent; |
c752666c1 [GFS2] Fix bug in... |
1000 |
} |
b3b94faa5 [GFS2] The core o... |
1001 |
dent = next; |
c752666c1 [GFS2] Fix bug in... |
1002 |
} while (dent); |
b3b94faa5 [GFS2] The core o... |
1003 |
|
c752666c1 [GFS2] Fix bug in... |
1004 |
oleaf->lf_depth = nleaf->lf_depth; |
b3b94faa5 [GFS2] The core o... |
1005 1006 |
error = gfs2_meta_inode_buffer(dip, &dibh); |
feaa7bba0 [GFS2] Fix unlink... |
1007 |
if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { |
b3b94faa5 [GFS2] The core o... |
1008 1009 1010 1011 1012 1013 1014 1015 1016 |
dip->i_di.di_blocks++; gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); } brelse(obh); brelse(nbh); return error; |
e90deff53 [GFS2] Fix bug in... |
1017 |
fail_lpfree: |
b3b94faa5 [GFS2] The core o... |
1018 |
kfree(lp); |
e90deff53 [GFS2] Fix bug in... |
1019 |
fail_brelse: |
b3b94faa5 [GFS2] The core o... |
1020 |
brelse(obh); |
b3b94faa5 [GFS2] The core o... |
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 |
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) { |
feaa7bba0 [GFS2] Fix unlink... |
1034 |
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
b3b94faa5 [GFS2] The core o... |
1035 |
struct buffer_head *dibh; |
cd915493f [GFS2] Change all... |
1036 1037 1038 1039 |
u32 hsize; u64 *buf; u64 *from, *to; u64 block; |
b3b94faa5 [GFS2] The core o... |
1040 1041 1042 1043 |
int x; int error = 0; hsize = 1 << dip->i_di.di_depth; |
cd915493f [GFS2] Change all... |
1044 |
if (hsize * sizeof(u64) != dip->i_di.di_size) { |
b3b94faa5 [GFS2] The core o... |
1045 1046 1047 1048 1049 1050 1051 1052 1053 |
gfs2_consist_inode(dip); return -EIO; } /* Allocate both the "from" and "to" buffers in one big chunk */ buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL); for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { |
e13940ba5 [GFS2] Make dir.c... |
1054 |
error = gfs2_dir_read_data(dip, (char *)buf, |
b3b94faa5 [GFS2] The core o... |
1055 |
block * sdp->sd_hash_bsize, |
7276b3b0c [GFS2] Tidy up me... |
1056 |
sdp->sd_hash_bsize, 1); |
b3b94faa5 [GFS2] The core o... |
1057 1058 1059 1060 1061 1062 1063 |
if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; goto fail; } from = buf; |
cd915493f [GFS2] Change all... |
1064 |
to = (u64 *)((char *)buf + sdp->sd_hash_bsize); |
b3b94faa5 [GFS2] The core o... |
1065 1066 1067 1068 1069 |
for (x = sdp->sd_hash_ptrs; x--; from++) { *to++ = *from; /* No endianess worries */ *to++ = *from; } |
e13940ba5 [GFS2] Make dir.c... |
1070 |
error = gfs2_dir_write_data(dip, |
b3b94faa5 [GFS2] The core o... |
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
(char *)buf + sdp->sd_hash_bsize, block * sdp->sd_sb.sb_bsize, sdp->sd_sb.sb_bsize); if (error != sdp->sd_sb.sb_bsize) { if (error >= 0) error = -EIO; goto fail; } } kfree(buf); error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { dip->i_di.di_depth++; gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); } return error; |
a91ea69ff [GFS2] Align all ... |
1091 |
fail: |
b3b94faa5 [GFS2] The core o... |
1092 |
kfree(buf); |
b3b94faa5 [GFS2] The core o... |
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 |
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 ... |
1109 |
const struct gfs2_dirent *dent_a, *dent_b; |
cd915493f [GFS2] Change all... |
1110 |
u32 hash_a, hash_b; |
b3b94faa5 [GFS2] The core o... |
1111 |
int ret = 0; |
2bdbc5d73 [GFS2] Directory ... |
1112 |
dent_a = *(const struct gfs2_dirent **)a; |
c752666c1 [GFS2] Fix bug in... |
1113 |
hash_a = be32_to_cpu(dent_a->de_hash); |
b3b94faa5 [GFS2] The core o... |
1114 |
|
2bdbc5d73 [GFS2] Directory ... |
1115 |
dent_b = *(const struct gfs2_dirent **)b; |
c752666c1 [GFS2] Fix bug in... |
1116 |
hash_b = be32_to_cpu(dent_b->de_hash); |
b3b94faa5 [GFS2] The core o... |
1117 1118 1119 1120 1121 1122 |
if (hash_a > hash_b) ret = 1; else if (hash_a < hash_b) ret = -1; else { |
4dd651adb [GFS2] Fix the bu... |
1123 1124 |
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... |
1125 1126 1127 1128 1129 1130 |
if (len_a > len_b) ret = 1; else if (len_a < len_b) ret = -1; else |
2bdbc5d73 [GFS2] Directory ... |
1131 |
ret = memcmp(dent_a + 1, dent_b + 1, len_a); |
b3b94faa5 [GFS2] The core o... |
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 |
} 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... |
1154 |
static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, |
b3b94faa5 [GFS2] The core o... |
1155 |
void *opaque, gfs2_filldir_t filldir, |
cd915493f [GFS2] Change all... |
1156 |
const struct gfs2_dirent **darr, u32 entries, |
b3b94faa5 [GFS2] The core o... |
1157 1158 |
int *copied) { |
71b86f562 [GFS2] Further up... |
1159 |
const struct gfs2_dirent *dent, *dent_next; |
629a21e7e [GFS2] split and ... |
1160 |
struct gfs2_inum_host inum; |
cd915493f [GFS2] Change all... |
1161 |
u64 off, off_next; |
b3b94faa5 [GFS2] The core o... |
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 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 |
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; } gfs2_inum_in(&inum, (char *)&dent->de_inum); |
2bdbc5d73 [GFS2] Directory ... |
1198 |
error = filldir(opaque, (const char *)(dent + 1), |
4dd651adb [GFS2] Fix the bu... |
1199 |
be16_to_cpu(dent->de_name_len), |
b3b94faa5 [GFS2] The core o... |
1200 |
off, &inum, |
4dd651adb [GFS2] Fix the bu... |
1201 |
be16_to_cpu(dent->de_type)); |
b3b94faa5 [GFS2] The core o... |
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 |
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; } |
71b86f562 [GFS2] Further up... |
1216 1217 1218 |
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, gfs2_filldir_t filldir, int *copied, unsigned *depth, u64 leaf_no) |
b3b94faa5 [GFS2] The core o... |
1219 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1220 |
struct gfs2_inode *ip = GFS2_I(inode); |
71b86f562 [GFS2] Further up... |
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 |
struct buffer_head *bh; struct gfs2_leaf *lf; unsigned entries = 0; 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... |
1231 |
|
b3b94faa5 [GFS2] The core o... |
1232 |
do { |
71b86f562 [GFS2] Further up... |
1233 |
error = get_leaf(ip, lfn, &bh); |
b3b94faa5 [GFS2] The core o... |
1234 |
if (error) |
71b86f562 [GFS2] Further up... |
1235 1236 1237 1238 1239 1240 1241 1242 1243 |
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... |
1244 1245 1246 |
if (!entries) return 0; |
71b86f562 [GFS2] Further up... |
1247 |
error = -ENOMEM; |
2bdbc5d73 [GFS2] Directory ... |
1248 |
larr = vmalloc((leaves + entries) * sizeof(void *)); |
71b86f562 [GFS2] Further up... |
1249 1250 1251 1252 1253 1254 |
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... |
1255 |
|
71b86f562 [GFS2] Further up... |
1256 1257 |
do { error = get_leaf(ip, lfn, &bh); |
b3b94faa5 [GFS2] The core o... |
1258 |
if (error) |
71b86f562 [GFS2] Further up... |
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 |
goto out_kfree; lf = (struct gfs2_leaf *)bh->b_data; lfn = be64_to_cpu(lf->lf_next); if (lf->lf_entries) { dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_gather, NULL, &g); error = PTR_ERR(dent); if (IS_ERR(dent)) { goto out_kfree; } error = 0; larr[leaf++] = bh; |
b3b94faa5 [GFS2] The core o... |
1271 |
} else { |
71b86f562 [GFS2] Further up... |
1272 |
brelse(bh); |
b3b94faa5 [GFS2] The core o... |
1273 |
} |
71b86f562 [GFS2] Further up... |
1274 |
} while(lfn); |
b3b94faa5 [GFS2] The core o... |
1275 |
|
71b86f562 [GFS2] Further up... |
1276 |
error = do_filldir_main(ip, offset, opaque, filldir, darr, |
b3b94faa5 [GFS2] The core o... |
1277 |
entries, copied); |
71b86f562 [GFS2] Further up... |
1278 1279 1280 |
out_kfree: for(i = 0; i < leaf; i++) brelse(larr[i]); |
fe1bdedc6 [GFS2] Use vmallo... |
1281 |
vfree(larr); |
71b86f562 [GFS2] Further up... |
1282 |
out: |
b3b94faa5 [GFS2] The core o... |
1283 1284 1285 1286 |
return error; } /** |
c752666c1 [GFS2] Fix bug in... |
1287 1288 1289 1290 1291 |
* 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... |
1292 |
* |
c752666c1 [GFS2] Fix bug in... |
1293 |
* Returns: errno |
b3b94faa5 [GFS2] The core o... |
1294 |
*/ |
cd915493f [GFS2] Change all... |
1295 |
static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, |
c752666c1 [GFS2] Fix bug in... |
1296 |
gfs2_filldir_t filldir) |
b3b94faa5 [GFS2] The core o... |
1297 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1298 1299 |
struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); |
cd915493f [GFS2] Change all... |
1300 1301 1302 |
u32 hsize, len = 0; u32 ht_offset, lp_offset, ht_offset_cur = -1; u32 hash, index; |
b44b84d76 [GFS2] gfs2 misc ... |
1303 |
__be64 *lp; |
c752666c1 [GFS2] Fix bug in... |
1304 1305 |
int copied = 0; int error = 0; |
4da3c6463 [GFS2] Fix a coup... |
1306 |
unsigned depth = 0; |
b3b94faa5 [GFS2] The core o... |
1307 1308 |
hsize = 1 << dip->i_di.di_depth; |
cd915493f [GFS2] Change all... |
1309 |
if (hsize * sizeof(u64) != dip->i_di.di_size) { |
b3b94faa5 [GFS2] The core o... |
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
gfs2_consist_inode(dip); return -EIO; } hash = gfs2_dir_offset2hash(*offset); index = hash >> (32 - dip->i_di.di_depth); lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); if (!lp) return -ENOMEM; while (index < hsize) { lp_offset = index & (sdp->sd_hash_ptrs - 1); ht_offset = index - lp_offset; if (ht_offset_cur != ht_offset) { |
e13940ba5 [GFS2] Make dir.c... |
1326 |
error = gfs2_dir_read_data(dip, (char *)lp, |
b44b84d76 [GFS2] gfs2 misc ... |
1327 |
ht_offset * sizeof(__be64), |
7276b3b0c [GFS2] Tidy up me... |
1328 |
sdp->sd_hash_bsize, 1); |
b3b94faa5 [GFS2] The core o... |
1329 1330 1331 1332 1333 1334 1335 |
if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; goto out; } ht_offset_cur = ht_offset; } |
71b86f562 [GFS2] Further up... |
1336 1337 1338 |
error = gfs2_dir_read_leaf(inode, offset, opaque, filldir, &copied, &depth, be64_to_cpu(lp[lp_offset])); |
b3b94faa5 [GFS2] The core o... |
1339 |
if (error) |
71b86f562 [GFS2] Further up... |
1340 |
break; |
b3b94faa5 [GFS2] The core o... |
1341 |
|
71b86f562 [GFS2] Further up... |
1342 |
len = 1 << (dip->i_di.di_depth - depth); |
b3b94faa5 [GFS2] The core o... |
1343 1344 |
index = (index & ~(len - 1)) + len; } |
71b86f562 [GFS2] Further up... |
1345 |
out: |
b3b94faa5 [GFS2] The core o... |
1346 |
kfree(lp); |
71b86f562 [GFS2] Further up... |
1347 1348 |
if (error > 0) error = 0; |
b3b94faa5 [GFS2] The core o... |
1349 1350 |
return error; } |
cd915493f [GFS2] Change all... |
1351 |
int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, |
71b86f562 [GFS2] Further up... |
1352 |
gfs2_filldir_t filldir) |
b3b94faa5 [GFS2] The core o... |
1353 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1354 |
struct gfs2_inode *dip = GFS2_I(inode); |
71b86f562 [GFS2] Further up... |
1355 1356 |
struct dirent_gather g; const struct gfs2_dirent **darr, *dent; |
b3b94faa5 [GFS2] The core o... |
1357 1358 1359 |
struct buffer_head *dibh; int copied = 0; int error; |
71b86f562 [GFS2] Further up... |
1360 1361 1362 1363 1364 |
if (!dip->i_di.di_entries) return 0; if (dip->i_di.di_flags & GFS2_DIF_EXHASH) return dir_e_read(inode, offset, opaque, filldir); |
b3b94faa5 [GFS2] The core o... |
1365 1366 1367 1368 |
if (!gfs2_is_stuffed(dip)) { gfs2_consist_inode(dip); return -EIO; } |
b3b94faa5 [GFS2] The core o... |
1369 1370 1371 |
error = gfs2_meta_inode_buffer(dip, &dibh); if (error) return error; |
71b86f562 [GFS2] Further up... |
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 |
error = -ENOMEM; darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *), GFP_KERNEL); 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; } error = do_filldir_main(dip, offset, opaque, filldir, darr, dip->i_di.di_entries, &copied); out: kfree(darr); } |
b3b94faa5 [GFS2] The core o... |
1389 1390 1391 1392 1393 1394 1395 |
if (error > 0) error = 0; brelse(dibh); return error; } |
b3b94faa5 [GFS2] The core o... |
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 |
/** * 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 */ |
c752666c1 [GFS2] Fix bug in... |
1407 |
int gfs2_dir_search(struct inode *dir, const struct qstr *name, |
629a21e7e [GFS2] split and ... |
1408 |
struct gfs2_inum_host *inum, unsigned int *type) |
b3b94faa5 [GFS2] The core o... |
1409 |
{ |
c752666c1 [GFS2] Fix bug in... |
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 |
struct buffer_head *bh; struct gfs2_dirent *dent; dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); if (dent) { if (IS_ERR(dent)) return PTR_ERR(dent); if (inum) gfs2_inum_in(inum, (char *)&dent->de_inum); if (type) *type = be16_to_cpu(dent->de_type); brelse(bh); return 0; } return -ENOENT; } static int dir_new_leaf(struct inode *inode, const struct qstr *name) { struct buffer_head *bh, *obh; |
feaa7bba0 [GFS2] Fix unlink... |
1430 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
1431 |
struct gfs2_leaf *leaf, *oleaf; |
b3b94faa5 [GFS2] The core o... |
1432 |
int error; |
c752666c1 [GFS2] Fix bug in... |
1433 1434 |
u32 index; u64 bn; |
b3b94faa5 [GFS2] The core o... |
1435 |
|
c752666c1 [GFS2] Fix bug in... |
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 |
index = name->hash >> (32 - ip->i_di.di_depth); 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... |
1450 |
|
c752666c1 [GFS2] Fix bug in... |
1451 1452 1453 1454 1455 1456 1457 |
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... |
1458 |
oleaf->lf_next = cpu_to_be64(bh->b_blocknr); |
c752666c1 [GFS2] Fix bug in... |
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 |
brelse(bh); brelse(obh); error = gfs2_meta_inode_buffer(ip, &bh); if (error) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_blocks++; gfs2_dinode_out(&ip->i_di, bh->b_data); brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 |
} /** * 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... |
1481 |
int gfs2_dir_add(struct inode *inode, const struct qstr *name, |
629a21e7e [GFS2] split and ... |
1482 |
const struct gfs2_inum_host *inum, unsigned type) |
b3b94faa5 [GFS2] The core o... |
1483 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1484 |
struct gfs2_inode *ip = GFS2_I(inode); |
c752666c1 [GFS2] Fix bug in... |
1485 1486 1487 |
struct buffer_head *bh; struct gfs2_dirent *dent; struct gfs2_leaf *leaf; |
b3b94faa5 [GFS2] The core o... |
1488 |
int error; |
c752666c1 [GFS2] Fix bug in... |
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 |
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); gfs2_inum_out(inum, (char *)&dent->de_inum); dent->de_type = cpu_to_be16(type); if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { leaf = (struct gfs2_leaf *)bh->b_data; leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1); } brelse(bh); error = gfs2_meta_inode_buffer(ip, &bh); if (error) break; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_entries++; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); gfs2_dinode_out(&ip->i_di, bh->b_data); brelse(bh); error = 0; break; } if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) { error = dir_make_exhash(inode); if (error) break; continue; } error = dir_split_leaf(inode, name); if (error == 0) continue; |
e90deff53 [GFS2] Fix bug in... |
1523 |
if (error < 0) |
c752666c1 [GFS2] Fix bug in... |
1524 1525 1526 1527 1528 1529 |
break; if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { error = dir_double_exhash(ip); if (error) break; error = dir_split_leaf(inode, name); |
e90deff53 [GFS2] Fix bug in... |
1530 |
if (error < 0) |
c752666c1 [GFS2] Fix bug in... |
1531 |
break; |
e90deff53 [GFS2] Fix bug in... |
1532 1533 |
if (error == 0) continue; |
c752666c1 [GFS2] Fix bug in... |
1534 1535 1536 1537 1538 1539 1540 |
} error = dir_new_leaf(inode, name); if (!error) continue; error = -ENOSPC; break; } |
b3b94faa5 [GFS2] The core o... |
1541 1542 |
return error; } |
c752666c1 [GFS2] Fix bug in... |
1543 |
|
b3b94faa5 [GFS2] The core o... |
1544 1545 1546 1547 1548 1549 1550 |
/** * gfs2_dir_del - Delete a directory entry * @dip: The GFS2 inode * @filename: The filename * * Returns: 0 on success, error code on failure */ |
c752666c1 [GFS2] Fix bug in... |
1551 |
int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
1552 |
{ |
c752666c1 [GFS2] Fix bug in... |
1553 1554 |
struct gfs2_dirent *dent, *prev = NULL; struct buffer_head *bh; |
b3b94faa5 [GFS2] The core o... |
1555 |
int error; |
c752666c1 [GFS2] Fix bug in... |
1556 1557 |
/* Returns _either_ the entry (if its first in block) or the previous entry otherwise */ |
feaa7bba0 [GFS2] Fix unlink... |
1558 |
dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh); |
c752666c1 [GFS2] Fix bug in... |
1559 1560 1561 1562 1563 1564 1565 1566 1567 |
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... |
1568 |
if (gfs2_dirent_find(dent, name, NULL) == 0) { |
c752666c1 [GFS2] Fix bug in... |
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 |
prev = dent; dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); } dirent_del(dip, bh, prev, dent); if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { 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... |
1580 |
} |
ed3865079 [GFS2] Finally ge... |
1581 |
brelse(bh); |
c752666c1 [GFS2] Fix bug in... |
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
error = gfs2_meta_inode_buffer(dip, &bh); if (error) return error; if (!dip->i_di.di_entries) gfs2_consist_inode(dip); gfs2_trans_add_bh(dip->i_gl, bh, 1); dip->i_di.di_entries--; dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); gfs2_dinode_out(&dip->i_di, bh->b_data); brelse(bh); |
feaa7bba0 [GFS2] Fix unlink... |
1594 |
mark_inode_dirty(&dip->i_inode); |
b3b94faa5 [GFS2] The core o... |
1595 1596 1597 |
return error; } |
b3b94faa5 [GFS2] The core o... |
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
/** * 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... |
1610 |
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, |
629a21e7e [GFS2] split and ... |
1611 |
struct gfs2_inum_host *inum, unsigned int new_type) |
b3b94faa5 [GFS2] The core o... |
1612 |
{ |
c752666c1 [GFS2] Fix bug in... |
1613 1614 |
struct buffer_head *bh; struct gfs2_dirent *dent; |
b3b94faa5 [GFS2] The core o... |
1615 |
int error; |
feaa7bba0 [GFS2] Fix unlink... |
1616 |
dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh); |
c752666c1 [GFS2] Fix bug in... |
1617 1618 1619 1620 1621 1622 |
if (!dent) { gfs2_consist_inode(dip); return -EIO; } if (IS_ERR(dent)) return PTR_ERR(dent); |
b3b94faa5 [GFS2] The core o... |
1623 |
|
c752666c1 [GFS2] Fix bug in... |
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 |
gfs2_trans_add_bh(dip->i_gl, bh, 1); gfs2_inum_out(inum, (char *)&dent->de_inum); dent->de_type = cpu_to_be16(new_type); if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { brelse(bh); error = gfs2_meta_inode_buffer(dip, &bh); if (error) return error; gfs2_trans_add_bh(dip->i_gl, bh, 1); } dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); gfs2_dinode_out(&dip->i_di, bh->b_data); brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 |
} /** * foreach_leaf - call a function for each leaf in a directory * @dip: the directory * @lc: the function to call for each each * @data: private data to pass to it * * Returns: errno */ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) { |
feaa7bba0 [GFS2] Fix unlink... |
1653 |
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
b3b94faa5 [GFS2] The core o... |
1654 |
struct buffer_head *bh; |
c752666c1 [GFS2] Fix bug in... |
1655 |
struct gfs2_leaf *leaf; |
cd915493f [GFS2] Change all... |
1656 1657 1658 |
u32 hsize, len; u32 ht_offset, lp_offset, ht_offset_cur = -1; u32 index = 0; |
b44b84d76 [GFS2] gfs2 misc ... |
1659 |
__be64 *lp; |
cd915493f [GFS2] Change all... |
1660 |
u64 leaf_no; |
b3b94faa5 [GFS2] The core o... |
1661 1662 1663 |
int error = 0; hsize = 1 << dip->i_di.di_depth; |
cd915493f [GFS2] Change all... |
1664 |
if (hsize * sizeof(u64) != dip->i_di.di_size) { |
b3b94faa5 [GFS2] The core o... |
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 |
gfs2_consist_inode(dip); return -EIO; } lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); if (!lp) return -ENOMEM; while (index < hsize) { lp_offset = index & (sdp->sd_hash_ptrs - 1); ht_offset = index - lp_offset; if (ht_offset_cur != ht_offset) { |
e13940ba5 [GFS2] Make dir.c... |
1678 |
error = gfs2_dir_read_data(dip, (char *)lp, |
b44b84d76 [GFS2] gfs2 misc ... |
1679 |
ht_offset * sizeof(__be64), |
7276b3b0c [GFS2] Tidy up me... |
1680 |
sdp->sd_hash_bsize, 1); |
b3b94faa5 [GFS2] The core o... |
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 |
if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; goto out; } ht_offset_cur = ht_offset; } leaf_no = be64_to_cpu(lp[lp_offset]); if (leaf_no) { error = get_leaf(dip, leaf_no, &bh); if (error) goto out; |
c752666c1 [GFS2] Fix bug in... |
1694 |
leaf = (struct gfs2_leaf *)bh->b_data; |
c752666c1 [GFS2] Fix bug in... |
1695 |
len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); |
634ee0b9f [GFS2] Fix use af... |
1696 |
brelse(bh); |
b3b94faa5 [GFS2] The core o... |
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 |
error = lc(dip, index, len, leaf_no, data); if (error) goto out; index = (index & ~(len - 1)) + len; } else index++; } if (index != hsize) { gfs2_consist_inode(dip); error = -EIO; } |
634ee0b9f [GFS2] Fix use af... |
1711 |
out: |
b3b94faa5 [GFS2] The core o... |
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
kfree(lp); return error; } /** * 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 * @data: not used * * Returns: errno */ |
cd915493f [GFS2] Change all... |
1727 1728 |
static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, u64 leaf_no, void *data) |
b3b94faa5 [GFS2] The core o... |
1729 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
1730 |
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
c752666c1 [GFS2] Fix bug in... |
1731 |
struct gfs2_leaf *tmp_leaf; |
b3b94faa5 [GFS2] The core o... |
1732 1733 |
struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; |
cd915493f [GFS2] Change all... |
1734 |
u64 blk, nblk; |
b3b94faa5 [GFS2] The core o... |
1735 1736 |
unsigned int rg_blocks = 0, l_blocks = 0; char *ht; |
cd915493f [GFS2] Change all... |
1737 |
unsigned int x, size = len * sizeof(u64); |
b3b94faa5 [GFS2] The core o... |
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 |
int error; memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); ht = kzalloc(size, GFP_KERNEL); if (!ht) return -ENOMEM; gfs2_alloc_get(dip); error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out; error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh); if (error) goto out_qs; /* Count the number of leaves */ |
c752666c1 [GFS2] Fix bug in... |
1757 |
for (blk = leaf_no; blk; blk = nblk) { |
b3b94faa5 [GFS2] The core o... |
1758 1759 1760 |
error = get_leaf(dip, blk, &bh); if (error) goto out_rlist; |
c752666c1 [GFS2] Fix bug in... |
1761 1762 |
tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); |
b3b94faa5 [GFS2] The core o... |
1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 |
brelse(bh); gfs2_rlist_add(sdp, &rlist, blk); l_blocks++; } gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; |
5c676f6d3 [GFS2] Macros rem... |
1773 |
rgd = rlist.rl_ghs[x].gh_gl->gl_object; |
b3b94faa5 [GFS2] The core o... |
1774 1775 1776 1777 1778 1779 1780 1781 |
rg_blocks += rgd->rd_ri.ri_length; } 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... |
1782 |
rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) + |
b3b94faa5 [GFS2] The core o... |
1783 1784 1785 |
RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks); if (error) goto out_rg_gunlock; |
c752666c1 [GFS2] Fix bug in... |
1786 |
for (blk = leaf_no; blk; blk = nblk) { |
b3b94faa5 [GFS2] The core o... |
1787 1788 1789 |
error = get_leaf(dip, blk, &bh); if (error) goto out_end_trans; |
c752666c1 [GFS2] Fix bug in... |
1790 1791 |
tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); |
b3b94faa5 [GFS2] The core o... |
1792 1793 1794 1795 1796 1797 1798 1799 |
brelse(bh); gfs2_free_meta(dip, blk, 1); if (!dip->i_di.di_blocks) gfs2_consist_inode(dip); dip->i_di.di_blocks--; } |
cd915493f [GFS2] Change all... |
1800 |
error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); |
b3b94faa5 [GFS2] The core o... |
1801 1802 1803 1804 1805 1806 1807 1808 1809 |
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... |
1810 |
gfs2_trans_add_bh(dip->i_gl, dibh, 1); |
b3b94faa5 [GFS2] The core o... |
1811 1812 |
gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); |
a91ea69ff [GFS2] Align all ... |
1813 |
out_end_trans: |
b3b94faa5 [GFS2] The core o... |
1814 |
gfs2_trans_end(sdp); |
a91ea69ff [GFS2] Align all ... |
1815 |
out_rg_gunlock: |
b3b94faa5 [GFS2] The core o... |
1816 |
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); |
a91ea69ff [GFS2] Align all ... |
1817 |
out_rlist: |
b3b94faa5 [GFS2] The core o... |
1818 1819 |
gfs2_rlist_free(&rlist); gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); |
a91ea69ff [GFS2] Align all ... |
1820 |
out_qs: |
b3b94faa5 [GFS2] The core o... |
1821 |
gfs2_quota_unhold(dip); |
a91ea69ff [GFS2] Align all ... |
1822 |
out: |
b3b94faa5 [GFS2] The core o... |
1823 1824 |
gfs2_alloc_put(dip); kfree(ht); |
b3b94faa5 [GFS2] The core o... |
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
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) { |
feaa7bba0 [GFS2] Fix unlink... |
1840 |
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
b3b94faa5 [GFS2] The core o... |
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 |
struct buffer_head *bh; int error; /* Dealloc on-disk leaves to FREEMETA state */ error = foreach_leaf(dip, leaf_dealloc, NULL); if (error) return error; /* Make this a regular file in case we crash. (We don't want to free these blocks a second time.) */ error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) return error; error = gfs2_meta_inode_buffer(dip, &bh); if (!error) { |
d4e9c4c3b [GFS2] Add an add... |
1858 |
gfs2_trans_add_bh(dip->i_gl, bh, 1); |
568f4c965 [GFS2] 80 Column ... |
1859 1860 |
((struct gfs2_dinode *)bh->b_data)->di_mode = cpu_to_be32(S_IFREG); |
b3b94faa5 [GFS2] The core o... |
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 |
brelse(bh); } gfs2_trans_end(sdp); return error; } /** * 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... |
1873 |
* |
c752666c1 [GFS2] Fix bug in... |
1874 |
* Returns: 1 if alloc required, 0 if not, -ve on error |
b3b94faa5 [GFS2] The core o... |
1875 |
*/ |
4d8012b60 [GFS2] Fix bug wh... |
1876 |
int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name) |
b3b94faa5 [GFS2] The core o... |
1877 |
{ |
c752666c1 [GFS2] Fix bug in... |
1878 1879 |
struct gfs2_dirent *dent; struct buffer_head *bh; |
b3b94faa5 [GFS2] The core o... |
1880 |
|
c752666c1 [GFS2] Fix bug in... |
1881 |
dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); |
ed3865079 [GFS2] Finally ge... |
1882 |
if (!dent) { |
c752666c1 [GFS2] Fix bug in... |
1883 |
return 1; |
ed3865079 [GFS2] Finally ge... |
1884 |
} |
c752666c1 [GFS2] Fix bug in... |
1885 1886 1887 1888 |
if (IS_ERR(dent)) return PTR_ERR(dent); brelse(bh); return 0; |
b3b94faa5 [GFS2] The core o... |
1889 |
} |