Blame view
fs/ext4/dir.c
14.1 KB
ac27a0ec1 [PATCH] ext4: ini... |
1 |
/* |
617ba13b3 [PATCH] ext4: ren... |
2 |
* linux/fs/ext4/dir.c |
ac27a0ec1 [PATCH] ext4: ini... |
3 4 5 6 7 8 9 10 11 12 13 14 |
* * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/dir.c * * Copyright (C) 1991, 1992 Linus Torvalds * |
617ba13b3 [PATCH] ext4: ren... |
15 |
* ext4 directory handling functions |
ac27a0ec1 [PATCH] ext4: ini... |
16 17 18 19 20 21 22 23 24 |
* * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 * * Hash Tree Directory indexing (c) 2001 Daniel Phillips * */ #include <linux/fs.h> |
dab291af8 [PATCH] jbd2: ena... |
25 |
#include <linux/jbd2.h> |
ac27a0ec1 [PATCH] ext4: ini... |
26 |
#include <linux/buffer_head.h> |
ac27a0ec1 [PATCH] ext4: ini... |
27 28 |
#include <linux/slab.h> #include <linux/rbtree.h> |
3dcf54515 ext4: move header... |
29 |
#include "ext4.h" |
ac27a0ec1 [PATCH] ext4: ini... |
30 |
|
617ba13b3 [PATCH] ext4: ren... |
31 |
static unsigned char ext4_filetype_table[] = { |
ac27a0ec1 [PATCH] ext4: ini... |
32 33 |
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; |
617ba13b3 [PATCH] ext4: ren... |
34 |
static int ext4_readdir(struct file *, void *, filldir_t); |
af5bc92dd ext4: Fix whitesp... |
35 36 37 38 |
static int ext4_dx_readdir(struct file *filp, void *dirent, filldir_t filldir); static int ext4_release_dir(struct inode *inode, struct file *filp); |
ac27a0ec1 [PATCH] ext4: ini... |
39 |
|
617ba13b3 [PATCH] ext4: ren... |
40 |
const struct file_operations ext4_dir_operations = { |
e0d10bfa9 ext4: improve lls... |
41 |
.llseek = ext4_llseek, |
ac27a0ec1 [PATCH] ext4: ini... |
42 |
.read = generic_read_dir, |
617ba13b3 [PATCH] ext4: ren... |
43 |
.readdir = ext4_readdir, /* we take BKL. needed?*/ |
5cdd7b2d7 Convert ext4 to u... |
44 |
.unlocked_ioctl = ext4_ioctl, |
ac27a0ec1 [PATCH] ext4: ini... |
45 |
#ifdef CONFIG_COMPAT |
617ba13b3 [PATCH] ext4: ren... |
46 |
.compat_ioctl = ext4_compat_ioctl, |
ac27a0ec1 [PATCH] ext4: ini... |
47 |
#endif |
642be6ec2 Remove incorrect ... |
48 |
.fsync = ext4_sync_file, |
617ba13b3 [PATCH] ext4: ren... |
49 |
.release = ext4_release_dir, |
ac27a0ec1 [PATCH] ext4: ini... |
50 51 52 53 54 |
}; static unsigned char get_dtype(struct super_block *sb, int filetype) { |
617ba13b3 [PATCH] ext4: ren... |
55 56 |
if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) || (filetype >= EXT4_FT_MAX)) |
ac27a0ec1 [PATCH] ext4: ini... |
57 |
return DT_UNKNOWN; |
617ba13b3 [PATCH] ext4: ren... |
58 |
return (ext4_filetype_table[filetype]); |
ac27a0ec1 [PATCH] ext4: ini... |
59 |
} |
cad3f0076 ext4: optimize ex... |
60 61 62 63 64 |
/* * Return 0 if the directory entry is OK, and 1 if there is a problem * * Note: this is the opposite of what ext2 and ext3 historically returned... */ |
60fd4da34 ext4: Cleanup ext... |
65 |
int __ext4_check_dir_entry(const char *function, unsigned int line, |
f7c21177a ext4: Use ext4_er... |
66 |
struct inode *dir, struct file *filp, |
60fd4da34 ext4: Cleanup ext... |
67 68 69 |
struct ext4_dir_entry_2 *de, struct buffer_head *bh, unsigned int offset) |
ac27a0ec1 [PATCH] ext4: ini... |
70 |
{ |
af5bc92dd ext4: Fix whitesp... |
71 |
const char *error_msg = NULL; |
3d0518f47 ext4: New rec_len... |
72 73 |
const int rlen = ext4_rec_len_from_disk(de->rec_len, dir->i_sb->s_blocksize); |
ac27a0ec1 [PATCH] ext4: ini... |
74 |
|
cad3f0076 ext4: optimize ex... |
75 |
if (unlikely(rlen < EXT4_DIR_REC_LEN(1))) |
ac27a0ec1 [PATCH] ext4: ini... |
76 |
error_msg = "rec_len is smaller than minimal"; |
cad3f0076 ext4: optimize ex... |
77 |
else if (unlikely(rlen % 4 != 0)) |
ac27a0ec1 [PATCH] ext4: ini... |
78 |
error_msg = "rec_len % 4 != 0"; |
cad3f0076 ext4: optimize ex... |
79 |
else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) |
ac27a0ec1 [PATCH] ext4: ini... |
80 |
error_msg = "rec_len is too small for name_len"; |
cad3f0076 ext4: optimize ex... |
81 82 |
else if (unlikely(((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)) |
ac27a0ec1 [PATCH] ext4: ini... |
83 |
error_msg = "directory entry across blocks"; |
cad3f0076 ext4: optimize ex... |
84 85 |
else if (unlikely(le32_to_cpu(de->inode) > le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) |
ac27a0ec1 [PATCH] ext4: ini... |
86 |
error_msg = "inode out of bounds"; |
cad3f0076 ext4: optimize ex... |
87 88 |
else return 0; |
f7c21177a ext4: Use ext4_er... |
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
if (filp) ext4_error_file(filp, function, line, bh ? bh->b_blocknr : 0, "bad entry in directory: %s - offset=%u(%u), " "inode=%u, rec_len=%d, name_len=%d", error_msg, (unsigned) (offset%bh->b_size), offset, le32_to_cpu(de->inode), rlen, de->name_len); else ext4_error_inode(dir, function, line, bh ? bh->b_blocknr : 0, "bad entry in directory: %s - offset=%u(%u), " "inode=%u, rec_len=%d, name_len=%d", error_msg, (unsigned) (offset%bh->b_size), offset, le32_to_cpu(de->inode), rlen, de->name_len); |
cad3f0076 ext4: optimize ex... |
103 |
return 1; |
ac27a0ec1 [PATCH] ext4: ini... |
104 |
} |
af5bc92dd ext4: Fix whitesp... |
105 106 |
static int ext4_readdir(struct file *filp, void *dirent, filldir_t filldir) |
ac27a0ec1 [PATCH] ext4: ini... |
107 108 |
{ int error = 0; |
498e5f241 ext4: Change unsi... |
109 |
unsigned int offset; |
ac27a0ec1 [PATCH] ext4: ini... |
110 |
int i, stored; |
617ba13b3 [PATCH] ext4: ren... |
111 |
struct ext4_dir_entry_2 *de; |
ac27a0ec1 [PATCH] ext4: ini... |
112 113 |
struct super_block *sb; int err; |
9d549890e [PATCH] ext4: cha... |
114 |
struct inode *inode = filp->f_path.dentry->d_inode; |
ac27a0ec1 [PATCH] ext4: ini... |
115 |
int ret = 0; |
9d9f17757 ext4: Avoid print... |
116 |
int dir_has_error = 0; |
ac27a0ec1 [PATCH] ext4: ini... |
117 118 |
sb = inode->i_sb; |
617ba13b3 [PATCH] ext4: ren... |
119 120 |
if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_COMPAT_DIR_INDEX) && |
12e9b8920 ext4: Use bitops ... |
121 |
((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) || |
ac27a0ec1 [PATCH] ext4: ini... |
122 |
((inode->i_size >> sb->s_blocksize_bits) == 1))) { |
617ba13b3 [PATCH] ext4: ren... |
123 |
err = ext4_dx_readdir(filp, dirent, filldir); |
ac27a0ec1 [PATCH] ext4: ini... |
124 125 126 127 128 129 130 131 |
if (err != ERR_BAD_DX_DIR) { ret = err; goto out; } /* * We don't set the inode dirty flag since it's not * critical that it get flushed back to the disk. */ |
07a038245 ext4: Convert mor... |
132 133 |
ext4_clear_inode_flag(filp->f_path.dentry->d_inode, EXT4_INODE_INDEX); |
ac27a0ec1 [PATCH] ext4: ini... |
134 |
} |
ac27a0ec1 [PATCH] ext4: ini... |
135 136 137 138 |
stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { |
2ed886852 ext4: Convert cal... |
139 |
struct ext4_map_blocks map; |
ac27a0ec1 [PATCH] ext4: ini... |
140 |
struct buffer_head *bh = NULL; |
2ed886852 ext4: Convert cal... |
141 142 143 |
map.m_lblk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb); map.m_len = 1; err = ext4_map_blocks(NULL, inode, &map, 0); |
ac27a0ec1 [PATCH] ext4: ini... |
144 |
if (err > 0) { |
2ed886852 ext4: Convert cal... |
145 |
pgoff_t index = map.m_pblk >> |
dc7868fcb readahead: conver... |
146 147 |
(PAGE_CACHE_SHIFT - inode->i_blkbits); if (!ra_has_index(&filp->f_ra, index)) |
cf914a7d6 readahead: split ... |
148 |
page_cache_sync_readahead( |
dc7868fcb readahead: conver... |
149 150 |
sb->s_bdev->bd_inode->i_mapping, &filp->f_ra, filp, |
cf914a7d6 readahead: split ... |
151 |
index, 1); |
f4e6b498d readahead: combin... |
152 |
filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; |
2ed886852 ext4: Convert cal... |
153 |
bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err); |
ac27a0ec1 [PATCH] ext4: ini... |
154 155 156 157 158 159 160 |
} /* * We ignore I/O errors on directories so users have a chance * of recovering data when there's a bad sector */ if (!bh) { |
9d9f17757 ext4: Avoid print... |
161 |
if (!dir_has_error) { |
f7c21177a ext4: Use ext4_er... |
162 163 164 |
EXT4_ERROR_FILE(filp, 0, "directory contains a " "hole at offset %llu", |
9d9f17757 ext4: Avoid print... |
165 166 167 |
(unsigned long long) filp->f_pos); dir_has_error = 1; } |
e6c402119 [PATCH] handle ex... |
168 169 170 |
/* corrupt size? Maybe no more blocks to read */ if (filp->f_pos > inode->i_blocks << 9) break; |
ac27a0ec1 [PATCH] ext4: ini... |
171 172 173 174 175 176 177 178 179 180 181 |
filp->f_pos += sb->s_blocksize - offset; continue; } revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { |
617ba13b3 [PATCH] ext4: ren... |
182 |
de = (struct ext4_dir_entry_2 *) |
ac27a0ec1 [PATCH] ext4: ini... |
183 184 185 186 187 188 189 |
(bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ |
3d0518f47 ext4: New rec_len... |
190 191 |
if (ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) < EXT4_DIR_REC_LEN(1)) |
ac27a0ec1 [PATCH] ext4: ini... |
192 |
break; |
3d0518f47 ext4: New rec_len... |
193 194 |
i += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); |
ac27a0ec1 [PATCH] ext4: ini... |
195 196 197 198 199 200 201 202 203 |
} offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { |
617ba13b3 [PATCH] ext4: ren... |
204 |
de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); |
f7c21177a ext4: Use ext4_er... |
205 |
if (ext4_check_dir_entry(inode, filp, de, |
cad3f0076 ext4: optimize ex... |
206 |
bh, offset)) { |
63f579335 [PATCH] ext4 whit... |
207 208 209 |
/* * On error, skip the f_pos to the next block */ |
ac27a0ec1 [PATCH] ext4: ini... |
210 211 |
filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1)) + 1; |
af5bc92dd ext4: Fix whitesp... |
212 |
brelse(bh); |
ac27a0ec1 [PATCH] ext4: ini... |
213 214 215 |
ret = stored; goto out; } |
3d0518f47 ext4: New rec_len... |
216 217 |
offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); |
ac27a0ec1 [PATCH] ext4: ini... |
218 219 220 221 222 223 224 225 |
if (le32_to_cpu(de->inode)) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ |
2b47c3611 Fix f_version typ... |
226 |
u64 version = filp->f_version; |
ac27a0ec1 [PATCH] ext4: ini... |
227 228 229 230 231 232 233 234 235 236 |
error = filldir(dirent, de->name, de->name_len, filp->f_pos, le32_to_cpu(de->inode), get_dtype(sb, de->file_type)); if (error) break; if (version != filp->f_version) goto revalidate; |
af5bc92dd ext4: Fix whitesp... |
237 |
stored++; |
ac27a0ec1 [PATCH] ext4: ini... |
238 |
} |
3d0518f47 ext4: New rec_len... |
239 240 |
filp->f_pos += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); |
ac27a0ec1 [PATCH] ext4: ini... |
241 242 |
} offset = 0; |
af5bc92dd ext4: Fix whitesp... |
243 |
brelse(bh); |
ac27a0ec1 [PATCH] ext4: ini... |
244 245 246 247 |
} out: return ret; } |
ac27a0ec1 [PATCH] ext4: ini... |
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
/* * These functions convert from the major/minor hash to an f_pos * value. * * Currently we only use major hash numer. This is unfortunate, but * on 32-bit machines, the same VFS interface is used for lseek and * llseek, so if we use the 64 bit offset, then the 32-bit versions of * lseek/telldir/seekdir will blow out spectacularly, and from within * the ext2 low-level routine, we don't know if we're being called by * a 64-bit version of the system call or the 32-bit version of the * system call. Worse yet, NFSv2 only allows for a 32-bit readdir * cookie. Sigh. */ #define hash2pos(major, minor) (major >> 1) #define pos2maj_hash(pos) ((pos << 1) & 0xffffffff) #define pos2min_hash(pos) (0) /* * This structure holds the nodes of the red-black tree used to store * the directory entry in hash order. */ struct fname { __u32 hash; __u32 minor_hash; struct rb_node rb_hash; struct fname *next; __u32 inode; __u8 name_len; __u8 file_type; char name[0]; }; /* * This functoin implements a non-recursive way of freeing all of the * nodes in the red-black tree. */ static void free_rb_tree_fname(struct rb_root *root) { struct rb_node *n = root->rb_node; struct rb_node *parent; struct fname *fname; while (n) { /* Do the node's children first */ |
69baee062 ext4: improve som... |
292 |
if (n->rb_left) { |
ac27a0ec1 [PATCH] ext4: ini... |
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
n = n->rb_left; continue; } if (n->rb_right) { n = n->rb_right; continue; } /* * The node has no children; free it, and then zero * out parent's link to it. Finally go to the * beginning of the loop and try to free the parent * node. */ parent = rb_parent(n); fname = rb_entry(n, struct fname, rb_hash); while (fname) { |
af5bc92dd ext4: Fix whitesp... |
309 |
struct fname *old = fname; |
ac27a0ec1 [PATCH] ext4: ini... |
310 |
fname = fname->next; |
af5bc92dd ext4: Fix whitesp... |
311 |
kfree(old); |
ac27a0ec1 [PATCH] ext4: ini... |
312 313 |
} if (!parent) |
64e290ec6 ext4: fix up rb_r... |
314 |
*root = RB_ROOT; |
ac27a0ec1 [PATCH] ext4: ini... |
315 316 317 318 319 320 |
else if (parent->rb_left == n) parent->rb_left = NULL; else if (parent->rb_right == n) parent->rb_right = NULL; n = parent; } |
ac27a0ec1 [PATCH] ext4: ini... |
321 |
} |
69baee062 ext4: improve som... |
322 |
static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos) |
ac27a0ec1 [PATCH] ext4: ini... |
323 324 |
{ struct dir_private_info *p; |
69baee062 ext4: improve som... |
325 |
p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL); |
ac27a0ec1 [PATCH] ext4: ini... |
326 327 |
if (!p) return NULL; |
ac27a0ec1 [PATCH] ext4: ini... |
328 329 |
p->curr_hash = pos2maj_hash(pos); p->curr_minor_hash = pos2min_hash(pos); |
ac27a0ec1 [PATCH] ext4: ini... |
330 331 |
return p; } |
617ba13b3 [PATCH] ext4: ren... |
332 |
void ext4_htree_free_dir_info(struct dir_private_info *p) |
ac27a0ec1 [PATCH] ext4: ini... |
333 334 335 336 337 338 339 340 |
{ free_rb_tree_fname(&p->root); kfree(p); } /* * Given a directory entry, enter it into the fname rb tree. */ |
617ba13b3 [PATCH] ext4: ren... |
341 |
int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, |
ac27a0ec1 [PATCH] ext4: ini... |
342 |
__u32 minor_hash, |
617ba13b3 [PATCH] ext4: ren... |
343 |
struct ext4_dir_entry_2 *dirent) |
ac27a0ec1 [PATCH] ext4: ini... |
344 345 |
{ struct rb_node **p, *parent = NULL; |
af5bc92dd ext4: Fix whitesp... |
346 |
struct fname *fname, *new_fn; |
ac27a0ec1 [PATCH] ext4: ini... |
347 348 |
struct dir_private_info *info; int len; |
a271fe852 ext4: Remove unne... |
349 |
info = dir_file->private_data; |
ac27a0ec1 [PATCH] ext4: ini... |
350 351 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 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
p = &info->root.rb_node; /* Create and allocate the fname structure */ len = sizeof(struct fname) + dirent->name_len + 1; new_fn = kzalloc(len, GFP_KERNEL); if (!new_fn) return -ENOMEM; new_fn->hash = hash; new_fn->minor_hash = minor_hash; new_fn->inode = le32_to_cpu(dirent->inode); new_fn->name_len = dirent->name_len; new_fn->file_type = dirent->file_type; memcpy(new_fn->name, dirent->name, dirent->name_len); new_fn->name[dirent->name_len] = 0; while (*p) { parent = *p; fname = rb_entry(parent, struct fname, rb_hash); /* * If the hash and minor hash match up, then we put * them on a linked list. This rarely happens... */ if ((new_fn->hash == fname->hash) && (new_fn->minor_hash == fname->minor_hash)) { new_fn->next = fname->next; fname->next = new_fn; return 0; } if (new_fn->hash < fname->hash) p = &(*p)->rb_left; else if (new_fn->hash > fname->hash) p = &(*p)->rb_right; else if (new_fn->minor_hash < fname->minor_hash) p = &(*p)->rb_left; else /* if (new_fn->minor_hash > fname->minor_hash) */ p = &(*p)->rb_right; } rb_link_node(&new_fn->rb_hash, parent, p); rb_insert_color(&new_fn->rb_hash, &info->root); return 0; } /* |
617ba13b3 [PATCH] ext4: ren... |
398 |
* This is a helper function for ext4_dx_readdir. It calls filldir |
ac27a0ec1 [PATCH] ext4: ini... |
399 400 401 |
* for all entres on the fname linked list. (Normally there is only * one entry on the linked list, unless there are 62 bit hash collisions.) */ |
af5bc92dd ext4: Fix whitesp... |
402 |
static int call_filldir(struct file *filp, void *dirent, |
ac27a0ec1 [PATCH] ext4: ini... |
403 404 405 406 |
filldir_t filldir, struct fname *fname) { struct dir_private_info *info = filp->private_data; loff_t curr_pos; |
9d549890e [PATCH] ext4: cha... |
407 |
struct inode *inode = filp->f_path.dentry->d_inode; |
af5bc92dd ext4: Fix whitesp... |
408 |
struct super_block *sb; |
ac27a0ec1 [PATCH] ext4: ini... |
409 410 411 412 413 |
int error; sb = inode->i_sb; if (!fname) { |
abda14189 ext4: Make printk... |
414 |
printk(KERN_ERR "EXT4-fs: call_filldir: called with " |
4776004f5 ext4: Add printk ... |
415 416 |
"null fname?!? "); |
ac27a0ec1 [PATCH] ext4: ini... |
417 418 419 420 421 422 423 424 425 426 |
return 0; } curr_pos = hash2pos(fname->hash, fname->minor_hash); while (fname) { error = filldir(dirent, fname->name, fname->name_len, curr_pos, fname->inode, get_dtype(sb, fname->file_type)); if (error) { filp->f_pos = curr_pos; |
d01564173 ext4: Fix ext4_dx... |
427 |
info->extra_fname = fname; |
ac27a0ec1 [PATCH] ext4: ini... |
428 429 430 431 432 433 |
return error; } fname = fname->next; } return 0; } |
af5bc92dd ext4: Fix whitesp... |
434 435 |
static int ext4_dx_readdir(struct file *filp, void *dirent, filldir_t filldir) |
ac27a0ec1 [PATCH] ext4: ini... |
436 437 |
{ struct dir_private_info *info = filp->private_data; |
9d549890e [PATCH] ext4: cha... |
438 |
struct inode *inode = filp->f_path.dentry->d_inode; |
ac27a0ec1 [PATCH] ext4: ini... |
439 440 441 442 |
struct fname *fname; int ret; if (!info) { |
69baee062 ext4: improve som... |
443 |
info = ext4_htree_create_dir_info(filp->f_pos); |
ac27a0ec1 [PATCH] ext4: ini... |
444 445 446 447 |
if (!info) return -ENOMEM; filp->private_data = info; } |
617ba13b3 [PATCH] ext4: ren... |
448 |
if (filp->f_pos == EXT4_HTREE_EOF) |
ac27a0ec1 [PATCH] ext4: ini... |
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 |
return 0; /* EOF */ /* Some one has messed with f_pos; reset the world */ if (info->last_pos != filp->f_pos) { free_rb_tree_fname(&info->root); info->curr_node = NULL; info->extra_fname = NULL; info->curr_hash = pos2maj_hash(filp->f_pos); info->curr_minor_hash = pos2min_hash(filp->f_pos); } /* * If there are any leftover names on the hash collision * chain, return them first. */ |
d01564173 ext4: Fix ext4_dx... |
464 465 466 |
if (info->extra_fname) { if (call_filldir(filp, dirent, filldir, info->extra_fname)) goto finished; |
d01564173 ext4: Fix ext4_dx... |
467 |
info->extra_fname = NULL; |
3c37fc86d ext4: Fix duplica... |
468 |
goto next_node; |
d01564173 ext4: Fix ext4_dx... |
469 |
} else if (!info->curr_node) |
ac27a0ec1 [PATCH] ext4: ini... |
470 471 472 473 474 475 476 477 478 479 480 481 482 |
info->curr_node = rb_first(&info->root); while (1) { /* * Fill the rbtree if we have no more entries, * or the inode has changed since we last read in the * cached entries. */ if ((!info->curr_node) || (filp->f_version != inode->i_version)) { info->curr_node = NULL; free_rb_tree_fname(&info->root); filp->f_version = inode->i_version; |
617ba13b3 [PATCH] ext4: ren... |
483 |
ret = ext4_htree_fill_tree(filp, info->curr_hash, |
ac27a0ec1 [PATCH] ext4: ini... |
484 485 486 487 488 |
info->curr_minor_hash, &info->next_hash); if (ret < 0) return ret; if (ret == 0) { |
617ba13b3 [PATCH] ext4: ren... |
489 |
filp->f_pos = EXT4_HTREE_EOF; |
ac27a0ec1 [PATCH] ext4: ini... |
490 491 492 493 494 495 496 497 498 499 |
break; } info->curr_node = rb_first(&info->root); } fname = rb_entry(info->curr_node, struct fname, rb_hash); info->curr_hash = fname->hash; info->curr_minor_hash = fname->minor_hash; if (call_filldir(filp, dirent, filldir, fname)) break; |
3c37fc86d ext4: Fix duplica... |
500 |
next_node: |
ac27a0ec1 [PATCH] ext4: ini... |
501 |
info->curr_node = rb_next(info->curr_node); |
3c37fc86d ext4: Fix duplica... |
502 503 504 505 506 507 |
if (info->curr_node) { fname = rb_entry(info->curr_node, struct fname, rb_hash); info->curr_hash = fname->hash; info->curr_minor_hash = fname->minor_hash; } else { |
ac27a0ec1 [PATCH] ext4: ini... |
508 |
if (info->next_hash == ~0) { |
617ba13b3 [PATCH] ext4: ren... |
509 |
filp->f_pos = EXT4_HTREE_EOF; |
ac27a0ec1 [PATCH] ext4: ini... |
510 511 512 513 514 515 516 517 518 519 |
break; } info->curr_hash = info->next_hash; info->curr_minor_hash = 0; } } finished: info->last_pos = filp->f_pos; return 0; } |
af5bc92dd ext4: Fix whitesp... |
520 |
static int ext4_release_dir(struct inode *inode, struct file *filp) |
ac27a0ec1 [PATCH] ext4: ini... |
521 |
{ |
63f579335 [PATCH] ext4 whit... |
522 |
if (filp->private_data) |
617ba13b3 [PATCH] ext4: ren... |
523 |
ext4_htree_free_dir_info(filp->private_data); |
ac27a0ec1 [PATCH] ext4: ini... |
524 525 526 |
return 0; } |