|
@@ -130,8 +130,50 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
|
|
return dquot_file_open(inode, filp);
|
|
return dquot_file_open(inode, filp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * ext4_llseek() copied from generic_file_llseek() to handle both
|
|
|
|
+ * block-mapped and extent-mapped maxbytes values. This should
|
|
|
|
+ * otherwise be identical with generic_file_llseek().
|
|
|
|
+ */
|
|
|
|
+loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
|
|
|
|
+{
|
|
|
|
+ struct inode *inode = file->f_mapping->host;
|
|
|
|
+ loff_t maxbytes;
|
|
|
|
+
|
|
|
|
+ if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
|
|
|
|
+ maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes;
|
|
|
|
+ else
|
|
|
|
+ maxbytes = inode->i_sb->s_maxbytes;
|
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
|
+ switch (origin) {
|
|
|
|
+ case SEEK_END:
|
|
|
|
+ offset += inode->i_size;
|
|
|
|
+ break;
|
|
|
|
+ case SEEK_CUR:
|
|
|
|
+ if (offset == 0) {
|
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
|
+ return file->f_pos;
|
|
|
|
+ }
|
|
|
|
+ offset += file->f_pos;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (offset < 0 || offset > maxbytes) {
|
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (offset != file->f_pos) {
|
|
|
|
+ file->f_pos = offset;
|
|
|
|
+ file->f_version = 0;
|
|
|
|
+ }
|
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
|
+
|
|
|
|
+ return offset;
|
|
|
|
+}
|
|
|
|
+
|
|
const struct file_operations ext4_file_operations = {
|
|
const struct file_operations ext4_file_operations = {
|
|
- .llseek = generic_file_llseek,
|
|
|
|
|
|
+ .llseek = ext4_llseek,
|
|
.read = do_sync_read,
|
|
.read = do_sync_read,
|
|
.write = do_sync_write,
|
|
.write = do_sync_write,
|
|
.aio_read = generic_file_aio_read,
|
|
.aio_read = generic_file_aio_read,
|