diff options
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 5520f8ad550..179f1c33ea5 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -64,6 +64,23 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) | |||
64 | return file->f_pos; | 64 | return file->f_pos; |
65 | offset += file->f_pos; | 65 | offset += file->f_pos; |
66 | break; | 66 | break; |
67 | case SEEK_DATA: | ||
68 | /* | ||
69 | * In the generic case the entire file is data, so as long as | ||
70 | * offset isn't at the end of the file then the offset is data. | ||
71 | */ | ||
72 | if (offset >= inode->i_size) | ||
73 | return -ENXIO; | ||
74 | break; | ||
75 | case SEEK_HOLE: | ||
76 | /* | ||
77 | * There is a virtual hole at the end of the file, so as long as | ||
78 | * offset isn't i_size or larger, return i_size. | ||
79 | */ | ||
80 | if (offset >= inode->i_size) | ||
81 | return -ENXIO; | ||
82 | offset = inode->i_size; | ||
83 | break; | ||
67 | } | 84 | } |
68 | 85 | ||
69 | if (offset < 0 && !unsigned_offsets(file)) | 86 | if (offset < 0 && !unsigned_offsets(file)) |
@@ -128,12 +145,13 @@ EXPORT_SYMBOL(no_llseek); | |||
128 | 145 | ||
129 | loff_t default_llseek(struct file *file, loff_t offset, int origin) | 146 | loff_t default_llseek(struct file *file, loff_t offset, int origin) |
130 | { | 147 | { |
148 | struct inode *inode = file->f_path.dentry->d_inode; | ||
131 | loff_t retval; | 149 | loff_t retval; |
132 | 150 | ||
133 | mutex_lock(&file->f_dentry->d_inode->i_mutex); | 151 | mutex_lock(&inode->i_mutex); |
134 | switch (origin) { | 152 | switch (origin) { |
135 | case SEEK_END: | 153 | case SEEK_END: |
136 | offset += i_size_read(file->f_path.dentry->d_inode); | 154 | offset += i_size_read(inode); |
137 | break; | 155 | break; |
138 | case SEEK_CUR: | 156 | case SEEK_CUR: |
139 | if (offset == 0) { | 157 | if (offset == 0) { |
@@ -141,6 +159,30 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) | |||
141 | goto out; | 159 | goto out; |
142 | } | 160 | } |
143 | offset += file->f_pos; | 161 | offset += file->f_pos; |
162 | break; | ||
163 | case SEEK_DATA: | ||
164 | /* | ||
165 | * In the generic case the entire file is data, so as | ||
166 | * long as offset isn't at the end of the file then the | ||
167 | * offset is data. | ||
168 | */ | ||
169 | if (offset >= inode->i_size) { | ||
170 | retval = -ENXIO; | ||
171 | goto out; | ||
172 | } | ||
173 | break; | ||
174 | case SEEK_HOLE: | ||
175 | /* | ||
176 | * There is a virtual hole at the end of the file, so | ||
177 | * as long as offset isn't i_size or larger, return | ||
178 | * i_size. | ||
179 | */ | ||
180 | if (offset >= inode->i_size) { | ||
181 | retval = -ENXIO; | ||
182 | goto out; | ||
183 | } | ||
184 | offset = inode->i_size; | ||
185 | break; | ||
144 | } | 186 | } |
145 | retval = -EINVAL; | 187 | retval = -EINVAL; |
146 | if (offset >= 0 || unsigned_offsets(file)) { | 188 | if (offset >= 0 || unsigned_offsets(file)) { |
@@ -151,7 +193,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) | |||
151 | retval = offset; | 193 | retval = offset; |
152 | } | 194 | } |
153 | out: | 195 | out: |
154 | mutex_unlock(&file->f_dentry->d_inode->i_mutex); | 196 | mutex_unlock(&inode->i_mutex); |
155 | return retval; | 197 | return retval; |
156 | } | 198 | } |
157 | EXPORT_SYMBOL(default_llseek); | 199 | EXPORT_SYMBOL(default_llseek); |