Commit f0494206 authored by Yan, Zheng's avatar Yan, Zheng

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: default avatarYan, Zheng <zheng.z.yan@intel.com>
Reviewed-by: default avatarAlex Elder <elder@linaro.org>
parent 0ccd5926
...@@ -190,7 +190,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx) ...@@ -190,7 +190,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx)
if (last) { if (last) {
/* remember our position */ /* remember our position */
fi->dentry = last; fi->dentry = last;
fi->next_offset = di->offset; fi->next_offset = fpos_off(di->offset);
} }
dput(dentry); dput(dentry);
return 0; return 0;
...@@ -369,9 +369,9 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) ...@@ -369,9 +369,9 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
fi->next_offset = 0; fi->next_offset = 0;
off = fi->next_offset; off = fi->next_offset;
} }
fi->frag = frag;
fi->offset = fi->next_offset; fi->offset = fi->next_offset;
fi->last_readdir = req; fi->last_readdir = req;
fi->frag = frag;
if (req->r_reply_info.dir_end) { if (req->r_reply_info.dir_end) {
kfree(fi->last_name); kfree(fi->last_name);
...@@ -474,7 +474,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) ...@@ -474,7 +474,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
{ {
struct ceph_file_info *fi = file->private_data; struct ceph_file_info *fi = file->private_data;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
loff_t old_offset = offset; loff_t old_offset = ceph_make_fpos(fi->frag, fi->next_offset);
loff_t retval; loff_t retval;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
...@@ -491,7 +491,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) ...@@ -491,7 +491,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
goto out; goto out;
} }
if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { if (offset >= 0) {
if (offset != file->f_pos) { if (offset != file->f_pos) {
file->f_pos = offset; file->f_pos = offset;
file->f_version = 0; file->f_version = 0;
...@@ -504,14 +504,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) ...@@ -504,14 +504,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
* seek to new frag, or seek prior to current chunk. * seek to new frag, or seek prior to current chunk.
*/ */
if (offset == 0 || if (offset == 0 ||
fpos_frag(offset) != fpos_frag(old_offset) || fpos_frag(offset) != fi->frag ||
fpos_off(offset) < fi->offset) { fpos_off(offset) < fi->offset) {
dout("dir_llseek dropping %p content\n", file); dout("dir_llseek dropping %p content\n", file);
reset_readdir(fi); reset_readdir(fi);
} }
/* bump dir_release_count if we did a forward seek */ /* bump dir_release_count if we did a forward seek */
if (offset > old_offset) if (fpos_cmp(offset, old_offset) > 0)
fi->dir_release_count--; fi->dir_release_count--;
} }
out: out:
......
...@@ -577,7 +577,7 @@ struct ceph_file_info { ...@@ -577,7 +577,7 @@ struct ceph_file_info {
/* readdir: position within a frag */ /* readdir: position within a frag */
unsigned offset; /* offset of last chunk, adjusted for . and .. */ unsigned offset; /* offset of last chunk, adjusted for . and .. */
u64 next_offset; /* offset of next chunk (last_name's + 1) */ unsigned next_offset; /* offset of next chunk (last_name's + 1) */
char *last_name; /* last entry in previous chunk */ char *last_name; /* last entry in previous chunk */
struct dentry *dentry; /* next dentry (for dcache readdir) */ struct dentry *dentry; /* next dentry (for dcache readdir) */
int dir_release_count; int dir_release_count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment