diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2014-02-27 03:26:24 -0500 |
---|---|---|
committer | Yan, Zheng <zheng.z.yan@intel.com> | 2014-04-02 22:33:52 -0400 |
commit | f0494206076703aaa0c8005eff41c413216ae26b (patch) | |
tree | e12b390f7d458c085fb91b9ebe220e4147dbe41c /fs/ceph/dir.c | |
parent | 0ccd59266973047770d5160318561c9189b79c93 (diff) |
ceph: fix ceph_dir_llseek()
Comparing offset with inode->i_sb->s_maxbytes doesn't make sense for
directory. For a fragmented directory, offset (frag_t, off) can be
larger than inode->i_sb->s_maxbytes.
At the very beginning of ceph_dir_llseek(), local variable old_offset
is initialized to parameter offset. This doesn't make sense neither.
Old_offset should be ceph_make_fpos(fi->frag, fi->next_offset).
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Diffstat (limited to 'fs/ceph/dir.c')
-rw-r--r-- | fs/ceph/dir.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 45eda6d7a40c..a7eaf9692aa6 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -190,7 +190,7 @@ more: | |||
190 | if (last) { | 190 | if (last) { |
191 | /* remember our position */ | 191 | /* remember our position */ |
192 | fi->dentry = last; | 192 | fi->dentry = last; |
193 | fi->next_offset = di->offset; | 193 | fi->next_offset = fpos_off(di->offset); |
194 | } | 194 | } |
195 | dput(dentry); | 195 | dput(dentry); |
196 | return 0; | 196 | return 0; |
@@ -369,9 +369,9 @@ more: | |||
369 | fi->next_offset = 0; | 369 | fi->next_offset = 0; |
370 | off = fi->next_offset; | 370 | off = fi->next_offset; |
371 | } | 371 | } |
372 | fi->frag = frag; | ||
372 | fi->offset = fi->next_offset; | 373 | fi->offset = fi->next_offset; |
373 | fi->last_readdir = req; | 374 | fi->last_readdir = req; |
374 | fi->frag = frag; | ||
375 | 375 | ||
376 | if (req->r_reply_info.dir_end) { | 376 | if (req->r_reply_info.dir_end) { |
377 | kfree(fi->last_name); | 377 | kfree(fi->last_name); |
@@ -474,7 +474,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) | |||
474 | { | 474 | { |
475 | struct ceph_file_info *fi = file->private_data; | 475 | struct ceph_file_info *fi = file->private_data; |
476 | struct inode *inode = file->f_mapping->host; | 476 | struct inode *inode = file->f_mapping->host; |
477 | loff_t old_offset = offset; | 477 | loff_t old_offset = ceph_make_fpos(fi->frag, fi->next_offset); |
478 | loff_t retval; | 478 | loff_t retval; |
479 | 479 | ||
480 | mutex_lock(&inode->i_mutex); | 480 | mutex_lock(&inode->i_mutex); |
@@ -491,7 +491,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) | |||
491 | goto out; | 491 | goto out; |
492 | } | 492 | } |
493 | 493 | ||
494 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { | 494 | if (offset >= 0) { |
495 | if (offset != file->f_pos) { | 495 | if (offset != file->f_pos) { |
496 | file->f_pos = offset; | 496 | file->f_pos = offset; |
497 | file->f_version = 0; | 497 | file->f_version = 0; |
@@ -504,14 +504,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) | |||
504 | * seek to new frag, or seek prior to current chunk. | 504 | * seek to new frag, or seek prior to current chunk. |
505 | */ | 505 | */ |
506 | if (offset == 0 || | 506 | if (offset == 0 || |
507 | fpos_frag(offset) != fpos_frag(old_offset) || | 507 | fpos_frag(offset) != fi->frag || |
508 | fpos_off(offset) < fi->offset) { | 508 | fpos_off(offset) < fi->offset) { |
509 | dout("dir_llseek dropping %p content\n", file); | 509 | dout("dir_llseek dropping %p content\n", file); |
510 | reset_readdir(fi); | 510 | reset_readdir(fi); |
511 | } | 511 | } |
512 | 512 | ||
513 | /* bump dir_release_count if we did a forward seek */ | 513 | /* bump dir_release_count if we did a forward seek */ |
514 | if (offset > old_offset) | 514 | if (fpos_cmp(offset, old_offset) > 0) |
515 | fi->dir_release_count--; | 515 | fi->dir_release_count--; |
516 | } | 516 | } |
517 | out: | 517 | out: |