aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_file.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index fb8dd34041eb..21a1c2b1c5fc 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -218,6 +218,15 @@ xfs_vm_fault(
218} 218}
219#endif /* CONFIG_XFS_DMAPI */ 219#endif /* CONFIG_XFS_DMAPI */
220 220
221/*
222 * Unfortunately we can't just use the clean and simple readdir implementation
223 * below, because nfs might call back into ->lookup from the filldir callback
224 * and that will deadlock the low-level btree code.
225 *
226 * Hopefully we'll find a better workaround that allows to use the optimal
227 * version at least for local readdirs for 2.6.25.
228 */
229#if 0
221STATIC int 230STATIC int
222xfs_file_readdir( 231xfs_file_readdir(
223 struct file *filp, 232 struct file *filp,
@@ -249,6 +258,126 @@ xfs_file_readdir(
249 return -error; 258 return -error;
250 return 0; 259 return 0;
251} 260}
261#else
262
263struct hack_dirent {
264 u64 ino;
265 loff_t offset;
266 int namlen;
267 unsigned int d_type;
268 char name[];
269};
270
271struct hack_callback {
272 char *dirent;
273 size_t len;
274 size_t used;
275};
276
277STATIC int
278xfs_hack_filldir(
279 void *__buf,
280 const char *name,
281 int namlen,
282 loff_t offset,
283 u64 ino,
284 unsigned int d_type)
285{
286 struct hack_callback *buf = __buf;
287 struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
288 unsigned int reclen;
289
290 reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64));
291 if (buf->used + reclen > buf->len)
292 return -EINVAL;
293
294 de->namlen = namlen;
295 de->offset = offset;
296 de->ino = ino;
297 de->d_type = d_type;
298 memcpy(de->name, name, namlen);
299 buf->used += reclen;
300 return 0;
301}
302
303STATIC int
304xfs_file_readdir(
305 struct file *filp,
306 void *dirent,
307 filldir_t filldir)
308{
309 struct inode *inode = filp->f_path.dentry->d_inode;
310 xfs_inode_t *ip = XFS_I(inode);
311 struct hack_callback buf;
312 struct hack_dirent *de;
313 int error;
314 loff_t size;
315 int eof = 0;
316 xfs_off_t start_offset, curr_offset, offset;
317
318 /*
319 * Try fairly hard to get memory
320 */
321 buf.len = PAGE_CACHE_SIZE;
322 do {
323 buf.dirent = kmalloc(buf.len, GFP_KERNEL);
324 if (buf.dirent)
325 break;
326 buf.len >>= 1;
327 } while (buf.len >= 1024);
328
329 if (!buf.dirent)
330 return -ENOMEM;
331
332 curr_offset = filp->f_pos;
333 if (curr_offset == 0x7fffffff)
334 offset = 0xffffffff;
335 else
336 offset = filp->f_pos;
337
338 while (!eof) {
339 unsigned int reclen;
340
341 start_offset = offset;
342
343 buf.used = 0;
344 error = -xfs_readdir(ip, &buf, buf.len, &offset,
345 xfs_hack_filldir);
346 if (error || offset == start_offset) {
347 size = 0;
348 break;
349 }
350
351 size = buf.used;
352 de = (struct hack_dirent *)buf.dirent;
353 curr_offset = de->offset /* & 0x7fffffff */;
354 while (size > 0) {
355 if (filldir(dirent, de->name, de->namlen,
356 curr_offset & 0x7fffffff,
357 de->ino, de->d_type)) {
358 goto done;
359 }
360
361 reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen,
362 sizeof(u64));
363 size -= reclen;
364 de = (struct hack_dirent *)((char *)de + reclen);
365 curr_offset = de->offset /* & 0x7fffffff */;
366 }
367 }
368
369 done:
370 if (!error) {
371 if (size == 0)
372 filp->f_pos = offset & 0x7fffffff;
373 else if (de)
374 filp->f_pos = curr_offset;
375 }
376
377 kfree(buf.dirent);
378 return error;
379}
380#endif
252 381
253STATIC int 382STATIC int
254xfs_file_mmap( 383xfs_file_mmap(