aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2012-04-30 14:11:29 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-22 16:00:15 -0400
commite8b96eb5034a0ccebf36760f88e31ea3e3cdf1e4 (patch)
tree3ea1b85311b3d059f2bbf38e484aa2ce06bab017 /fs
parent4ea425b63a3dfeb7707fc7cc7161c11a51e871ed (diff)
vfs: allow custom EOF in generic_file_llseek code
For ext3/4 htree directories, using the vfs llseek function with SEEK_END goes to i_size like for any other file, but in reality we want the maximum possible hash value. Recent changes in ext4 have cut & pasted generic_file_llseek() back into fs/ext4/dir.c, but replicating this core code seems like a bad idea, especially since the copy has already diverged from the vfs. This patch updates generic_file_llseek_size to accept both a custom maximum offset, and a custom EOF position. With this in place, ext4_dir_llseek can pass in the appropriate maximum hash position for both maxsize and eof, and get what it wants. As far as I know, this does not fix any bugs - nfs in the kernel doesn't use SEEK_END, and I don't know of any user who does. But some ext4 folks seem keen on doing the right thing here, and I can't really argue. (Patch also fixes up some comments slightly) Signed-off-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext3/dir.c3
-rw-r--r--fs/ext4/file.c3
-rw-r--r--fs/read_write.c18
3 files changed, 14 insertions, 10 deletions
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 92490e9f85ca..901f67e37864 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -303,7 +303,8 @@ loff_t ext3_dir_llseek(struct file *file, loff_t offset, int origin)
303 303
304 if (likely(dx_dir)) 304 if (likely(dx_dir))
305 return generic_file_llseek_size(file, offset, origin, 305 return generic_file_llseek_size(file, offset, origin,
306 ext3_get_htree_eof(file)); 306 ext3_get_htree_eof(file),
307 i_size_read(inode));
307 else 308 else
308 return generic_file_llseek(file, offset, origin); 309 return generic_file_llseek(file, offset, origin);
309} 310}
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 8c7642a00054..f3dadd0a0d51 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -225,7 +225,8 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
225 else 225 else
226 maxbytes = inode->i_sb->s_maxbytes; 226 maxbytes = inode->i_sb->s_maxbytes;
227 227
228 return generic_file_llseek_size(file, offset, origin, maxbytes); 228 return generic_file_llseek_size(file, offset, origin,
229 maxbytes, i_size_read(inode));
229} 230}
230 231
231const struct file_operations ext4_file_operations = { 232const struct file_operations ext4_file_operations = {
diff --git a/fs/read_write.c b/fs/read_write.c
index c20614f86c01..1adfb691e4f1 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -55,10 +55,11 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
55 * @file: file structure to seek on 55 * @file: file structure to seek on
56 * @offset: file offset to seek to 56 * @offset: file offset to seek to
57 * @origin: type of seek 57 * @origin: type of seek
58 * @size: max size of file system 58 * @size: max size of this file in file system
59 * @eof: offset used for SEEK_END position
59 * 60 *
60 * This is a variant of generic_file_llseek that allows passing in a custom 61 * This is a variant of generic_file_llseek that allows passing in a custom
61 * file size. 62 * maximum file size and a custom EOF position, for e.g. hashed directories
62 * 63 *
63 * Synchronization: 64 * Synchronization:
64 * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms) 65 * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
@@ -67,13 +68,13 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
67 */ 68 */
68loff_t 69loff_t
69generic_file_llseek_size(struct file *file, loff_t offset, int origin, 70generic_file_llseek_size(struct file *file, loff_t offset, int origin,
70 loff_t maxsize) 71 loff_t maxsize, loff_t eof)
71{ 72{
72 struct inode *inode = file->f_mapping->host; 73 struct inode *inode = file->f_mapping->host;
73 74
74 switch (origin) { 75 switch (origin) {
75 case SEEK_END: 76 case SEEK_END:
76 offset += i_size_read(inode); 77 offset += eof;
77 break; 78 break;
78 case SEEK_CUR: 79 case SEEK_CUR:
79 /* 80 /*
@@ -99,7 +100,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
99 * In the generic case the entire file is data, so as long as 100 * In the generic case the entire file is data, so as long as
100 * offset isn't at the end of the file then the offset is data. 101 * offset isn't at the end of the file then the offset is data.
101 */ 102 */
102 if (offset >= i_size_read(inode)) 103 if (offset >= eof)
103 return -ENXIO; 104 return -ENXIO;
104 break; 105 break;
105 case SEEK_HOLE: 106 case SEEK_HOLE:
@@ -107,9 +108,9 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
107 * There is a virtual hole at the end of the file, so as long as 108 * There is a virtual hole at the end of the file, so as long as
108 * offset isn't i_size or larger, return i_size. 109 * offset isn't i_size or larger, return i_size.
109 */ 110 */
110 if (offset >= i_size_read(inode)) 111 if (offset >= eof)
111 return -ENXIO; 112 return -ENXIO;
112 offset = i_size_read(inode); 113 offset = eof;
113 break; 114 break;
114 } 115 }
115 116
@@ -132,7 +133,8 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
132 struct inode *inode = file->f_mapping->host; 133 struct inode *inode = file->f_mapping->host;
133 134
134 return generic_file_llseek_size(file, offset, origin, 135 return generic_file_llseek_size(file, offset, origin,
135 inode->i_sb->s_maxbytes); 136 inode->i_sb->s_maxbytes,
137 i_size_read(inode));
136} 138}
137EXPORT_SYMBOL(generic_file_llseek); 139EXPORT_SYMBOL(generic_file_llseek);
138 140