diff options
author | Eric Sandeen <sandeen@redhat.com> | 2012-04-30 14:14:03 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-22 16:00:28 -0400 |
commit | ec7268ce21b379a248705548573393e4f346b20b (patch) | |
tree | b1723de44f1d4e29082659157da1b676b51b5a3b /fs | |
parent | e8b96eb5034a0ccebf36760f88e31ea3e3cdf1e4 (diff) |
ext4: use core vfs llseek code for dir seeks
Use the new functionality in generic_file_llseek_size() to
accept a custom EOF position, and un-cut-and-paste all the
vfs llseek code from ext4.
Also fix up comments on ext4_llseek() to reflect reality.
Signed-off-by: Eric Sandeen <sandeen@redaht.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/dir.c | 75 | ||||
-rw-r--r-- | fs/ext4/file.c | 6 |
2 files changed, 17 insertions, 64 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index aa39e600d159..8e07d2a5a139 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -324,74 +324,27 @@ static inline loff_t ext4_get_htree_eof(struct file *filp) | |||
324 | 324 | ||
325 | 325 | ||
326 | /* | 326 | /* |
327 | * ext4_dir_llseek() based on generic_file_llseek() to handle both | 327 | * ext4_dir_llseek() calls generic_file_llseek_size to handle htree |
328 | * non-htree and htree directories, where the "offset" is in terms | 328 | * directories, where the "offset" is in terms of the filename hash |
329 | * of the filename hash value instead of the byte offset. | 329 | * value instead of the byte offset. |
330 | * | 330 | * |
331 | * NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX) | 331 | * Because we may return a 64-bit hash that is well beyond offset limits, |
332 | * will be invalid once the directory was converted into a dx directory | 332 | * we need to pass the max hash as the maximum allowable offset in |
333 | * the htree directory case. | ||
334 | * | ||
335 | * For non-htree, ext4_llseek already chooses the proper max offset. | ||
333 | */ | 336 | */ |
334 | loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin) | 337 | loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin) |
335 | { | 338 | { |
336 | struct inode *inode = file->f_mapping->host; | 339 | struct inode *inode = file->f_mapping->host; |
337 | loff_t ret = -EINVAL; | ||
338 | int dx_dir = is_dx_dir(inode); | 340 | int dx_dir = is_dx_dir(inode); |
341 | loff_t htree_max = ext4_get_htree_eof(file); | ||
339 | 342 | ||
340 | mutex_lock(&inode->i_mutex); | 343 | if (likely(dx_dir)) |
341 | 344 | return generic_file_llseek_size(file, offset, origin, | |
342 | /* NOTE: relative offsets with dx directories might not work | 345 | htree_max, htree_max); |
343 | * as expected, as it is difficult to figure out the | 346 | else |
344 | * correct offset between dx hashes */ | 347 | return ext4_llseek(file, offset, origin); |
345 | |||
346 | switch (origin) { | ||
347 | case SEEK_END: | ||
348 | if (unlikely(offset > 0)) | ||
349 | goto out_err; /* not supported for directories */ | ||
350 | |||
351 | /* so only negative offsets are left, does that have a | ||
352 | * meaning for directories at all? */ | ||
353 | if (dx_dir) | ||
354 | offset += ext4_get_htree_eof(file); | ||
355 | else | ||
356 | offset += inode->i_size; | ||
357 | break; | ||
358 | case SEEK_CUR: | ||
359 | /* | ||
360 | * Here we special-case the lseek(fd, 0, SEEK_CUR) | ||
361 | * position-querying operation. Avoid rewriting the "same" | ||
362 | * f_pos value back to the file because a concurrent read(), | ||
363 | * write() or lseek() might have altered it | ||
364 | */ | ||
365 | if (offset == 0) { | ||
366 | offset = file->f_pos; | ||
367 | goto out_ok; | ||
368 | } | ||
369 | |||
370 | offset += file->f_pos; | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | if (unlikely(offset < 0)) | ||
375 | goto out_err; | ||
376 | |||
377 | if (!dx_dir) { | ||
378 | if (offset > inode->i_sb->s_maxbytes) | ||
379 | goto out_err; | ||
380 | } else if (offset > ext4_get_htree_eof(file)) | ||
381 | goto out_err; | ||
382 | |||
383 | /* Special lock needed here? */ | ||
384 | if (offset != file->f_pos) { | ||
385 | file->f_pos = offset; | ||
386 | file->f_version = 0; | ||
387 | } | ||
388 | |||
389 | out_ok: | ||
390 | ret = offset; | ||
391 | out_err: | ||
392 | mutex_unlock(&inode->i_mutex); | ||
393 | |||
394 | return ret; | ||
395 | } | 348 | } |
396 | 349 | ||
397 | /* | 350 | /* |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index f3dadd0a0d51..782eecb57e43 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -211,9 +211,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
211 | } | 211 | } |
212 | 212 | ||
213 | /* | 213 | /* |
214 | * ext4_llseek() copied from generic_file_llseek() to handle both | 214 | * ext4_llseek() handles both block-mapped and extent-mapped maxbytes values |
215 | * block-mapped and extent-mapped maxbytes values. This should | 215 | * by calling generic_file_llseek_size() with the appropriate maxbytes |
216 | * otherwise be identical with generic_file_llseek(). | 216 | * value for each. |
217 | */ | 217 | */ |
218 | loff_t ext4_llseek(struct file *file, loff_t offset, int origin) | 218 | loff_t ext4_llseek(struct file *file, loff_t offset, int origin) |
219 | { | 219 | { |