diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2005-10-11 11:29:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-11 12:46:54 -0400 |
commit | 19cba8abd6ca09527c194864ae651db65cbacfe1 (patch) | |
tree | 3d59a1e147b2701d0957bef392e2fda441d5143f /fs/9p/vfs_file.c | |
parent | ad6ce87e5bd4440a6ce9aa9f8cda795b9e902eff (diff) |
[PATCH] v9fs: remove additional buffer allocation from v9fs_file_read and v9fs_file_write
v9fs_file_read and v9fs_file_write use kmalloc to allocate buffers as big
as the data buffer received as parameter. kmalloc cannot be used to
allocate buffers bigger than 128K, so reading/writing data in chunks bigger
than 128k fails.
This patch reorganizes v9fs_file_read and v9fs_file_write to allocate only
buffers as big as the maximum data that can be sent in one 9P message.
Signed-off-by: Latchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r-- | fs/9p/vfs_file.c | 114 |
1 files changed, 33 insertions, 81 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index a4799e971d1c..bbc3cc63854f 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -175,16 +175,16 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | /** | 177 | /** |
178 | * v9fs_read - read from a file (internal) | 178 | * v9fs_file_read - read from a file |
179 | * @filep: file pointer to read | 179 | * @filep: file pointer to read |
180 | * @data: data buffer to read data into | 180 | * @data: data buffer to read data into |
181 | * @count: size of buffer | 181 | * @count: size of buffer |
182 | * @offset: offset at which to read data | 182 | * @offset: offset at which to read data |
183 | * | 183 | * |
184 | */ | 184 | */ |
185 | |||
186 | static ssize_t | 185 | static ssize_t |
187 | v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | 186 | v9fs_file_read(struct file *filp, char __user * data, size_t count, |
187 | loff_t * offset) | ||
188 | { | 188 | { |
189 | struct inode *inode = filp->f_dentry->d_inode; | 189 | struct inode *inode = filp->f_dentry->d_inode; |
190 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 190 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
@@ -194,6 +194,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
194 | int rsize = 0; | 194 | int rsize = 0; |
195 | int result = 0; | 195 | int result = 0; |
196 | int total = 0; | 196 | int total = 0; |
197 | int n; | ||
197 | 198 | ||
198 | dprintk(DEBUG_VFS, "\n"); | 199 | dprintk(DEBUG_VFS, "\n"); |
199 | 200 | ||
@@ -216,10 +217,15 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
216 | } else | 217 | } else |
217 | *offset += result; | 218 | *offset += result; |
218 | 219 | ||
219 | /* XXX - extra copy */ | 220 | n = copy_to_user(data, fcall->params.rread.data, result); |
220 | memcpy(buffer, fcall->params.rread.data, result); | 221 | if (n) { |
222 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); | ||
223 | kfree(fcall); | ||
224 | return -EFAULT; | ||
225 | } | ||
226 | |||
221 | count -= result; | 227 | count -= result; |
222 | buffer += result; | 228 | data += result; |
223 | total += result; | 229 | total += result; |
224 | 230 | ||
225 | kfree(fcall); | 231 | kfree(fcall); |
@@ -232,42 +238,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
232 | } | 238 | } |
233 | 239 | ||
234 | /** | 240 | /** |
235 | * v9fs_file_read - read from a file | 241 | * v9fs_file_write - write to a file |
236 | * @filep: file pointer to read | ||
237 | * @data: data buffer to read data into | ||
238 | * @count: size of buffer | ||
239 | * @offset: offset at which to read data | ||
240 | * | ||
241 | */ | ||
242 | |||
243 | static ssize_t | ||
244 | v9fs_file_read(struct file *filp, char __user * data, size_t count, | ||
245 | loff_t * offset) | ||
246 | { | ||
247 | int retval = -1; | ||
248 | int ret = 0; | ||
249 | char *buffer; | ||
250 | |||
251 | buffer = kmalloc(count, GFP_KERNEL); | ||
252 | if (!buffer) | ||
253 | return -ENOMEM; | ||
254 | |||
255 | retval = v9fs_read(filp, buffer, count, offset); | ||
256 | if (retval > 0) { | ||
257 | if ((ret = copy_to_user(data, buffer, retval)) != 0) { | ||
258 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", | ||
259 | ret); | ||
260 | retval = ret; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | kfree(buffer); | ||
265 | |||
266 | return retval; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * v9fs_write - write to a file | ||
271 | * @filep: file pointer to write | 242 | * @filep: file pointer to write |
272 | * @data: data buffer to write data from | 243 | * @data: data buffer to write data from |
273 | * @count: size of buffer | 244 | * @count: size of buffer |
@@ -276,7 +247,8 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count, | |||
276 | */ | 247 | */ |
277 | 248 | ||
278 | static ssize_t | 249 | static ssize_t |
279 | v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | 250 | v9fs_file_write(struct file *filp, const char __user * data, |
251 | size_t count, loff_t * offset) | ||
280 | { | 252 | { |
281 | struct inode *inode = filp->f_dentry->d_inode; | 253 | struct inode *inode = filp->f_dentry->d_inode; |
282 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 254 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
@@ -286,30 +258,42 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
286 | int result = -EIO; | 258 | int result = -EIO; |
287 | int rsize = 0; | 259 | int rsize = 0; |
288 | int total = 0; | 260 | int total = 0; |
261 | char *buf; | ||
289 | 262 | ||
290 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count, | 263 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, |
291 | (int)*offset); | 264 | (int)*offset); |
292 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | 265 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; |
293 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) | 266 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) |
294 | rsize = v9fid->iounit; | 267 | rsize = v9fid->iounit; |
295 | 268 | ||
296 | dump_data(buffer, count); | 269 | buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL); |
270 | if (!buf) | ||
271 | return -ENOMEM; | ||
297 | 272 | ||
298 | do { | 273 | do { |
299 | if (count < rsize) | 274 | if (count < rsize) |
300 | rsize = count; | 275 | rsize = count; |
301 | 276 | ||
302 | result = | 277 | result = copy_from_user(buf, data, rsize); |
303 | v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); | 278 | if (result) { |
279 | dprintk(DEBUG_ERROR, "Problem copying from user\n"); | ||
280 | kfree(buf); | ||
281 | return -EFAULT; | ||
282 | } | ||
283 | |||
284 | dump_data(buf, rsize); | ||
285 | result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall); | ||
304 | if (result < 0) { | 286 | if (result < 0) { |
305 | eprintk(KERN_ERR, "error while writing: %s(%d)\n", | 287 | eprintk(KERN_ERR, "error while writing: %s(%d)\n", |
306 | FCALL_ERROR(fcall), result); | 288 | FCALL_ERROR(fcall), result); |
307 | kfree(fcall); | 289 | kfree(fcall); |
290 | kfree(buf); | ||
308 | return result; | 291 | return result; |
309 | } else | 292 | } else |
310 | *offset += result; | 293 | *offset += result; |
311 | 294 | ||
312 | kfree(fcall); | 295 | kfree(fcall); |
296 | fcall = NULL; | ||
313 | 297 | ||
314 | if (result != rsize) { | 298 | if (result != rsize) { |
315 | eprintk(KERN_ERR, | 299 | eprintk(KERN_ERR, |
@@ -319,46 +303,14 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
319 | } | 303 | } |
320 | 304 | ||
321 | count -= result; | 305 | count -= result; |
322 | buffer += result; | 306 | data += result; |
323 | total += result; | 307 | total += result; |
324 | } while (count); | 308 | } while (count); |
325 | 309 | ||
310 | kfree(buf); | ||
326 | return total; | 311 | return total; |
327 | } | 312 | } |
328 | 313 | ||
329 | /** | ||
330 | * v9fs_file_write - write to a file | ||
331 | * @filep: file pointer to write | ||
332 | * @data: data buffer to write data from | ||
333 | * @count: size of buffer | ||
334 | * @offset: offset at which to write data | ||
335 | * | ||
336 | */ | ||
337 | |||
338 | static ssize_t | ||
339 | v9fs_file_write(struct file *filp, const char __user * data, | ||
340 | size_t count, loff_t * offset) | ||
341 | { | ||
342 | int ret = -1; | ||
343 | char *buffer; | ||
344 | |||
345 | buffer = kmalloc(count, GFP_KERNEL); | ||
346 | if (buffer == NULL) | ||
347 | return -ENOMEM; | ||
348 | |||
349 | ret = copy_from_user(buffer, data, count); | ||
350 | if (ret) { | ||
351 | dprintk(DEBUG_ERROR, "Problem copying from user\n"); | ||
352 | ret = -EFAULT; | ||
353 | } else { | ||
354 | ret = v9fs_write(filp, buffer, count, offset); | ||
355 | } | ||
356 | |||
357 | kfree(buffer); | ||
358 | |||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | struct file_operations v9fs_file_operations = { | 314 | struct file_operations v9fs_file_operations = { |
363 | .llseek = generic_file_llseek, | 315 | .llseek = generic_file_llseek, |
364 | .read = v9fs_file_read, | 316 | .read = v9fs_file_read, |