提交 63580e51 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull VFS patches (part 1) from Al Viro:
 "The major change in this pile is ->readdir() replacement with
  ->iterate(), dealing with ->f_pos races in ->readdir() instances for
  good.

  There's a lot more, but I'd prefer to split the pull request into
  several stages and this is the first obvious cutoff point."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (67 commits)
  [readdir] constify ->actor
  [readdir] ->readdir() is gone
  [readdir] convert ecryptfs
  [readdir] convert coda
  [readdir] convert ocfs2
  [readdir] convert fatfs
  [readdir] convert xfs
  [readdir] convert btrfs
  [readdir] convert hostfs
  [readdir] convert afs
  [readdir] convert ncpfs
  [readdir] convert hfsplus
  [readdir] convert hfs
  [readdir] convert befs
  [readdir] convert cifs
  [readdir] convert freevxfs
  [readdir] convert fuse
  [readdir] convert hpfs
  reiserfs: switch reiserfs_readdir_dentry to inode
  reiserfs: is_privroot_deh() needs only directory inode, actually
  ...
......@@ -414,7 +414,7 @@ prototypes:
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
......
......@@ -445,3 +445,9 @@ object doesn't exist. It's remote/distributed ones that might care...
[mandatory]
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
in your dentry operations instead.
--
[mandatory]
vfs_readdir() is gone; switch to iterate_dir() instead
--
[mandatory]
->readdir() is gone now; switch to ->iterate()
......@@ -777,7 +777,7 @@ struct file_operations {
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
......@@ -815,7 +815,7 @@ otherwise noted.
aio_write: called by io_submit(2) and other asynchronous I/O operations
readdir: called when the VFS needs to read the directory contents
iterate: called when the VFS needs to read the directory contents
poll: called by the VFS when a process wants to check if there is
activity on this file and (optionally) go to sleep until there
......
......@@ -354,9 +354,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
#define kern_addr_valid(addr) (1)
#endif
#define io_remap_pfn_range(vma, start, pfn, size, prot) \
remap_pfn_range(vma, start, pfn, size, prot)
#define pte_ERROR(e) \
printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
#define pmd_ERROR(e) \
......
......@@ -96,6 +96,7 @@ struct osf_dirent {
};
struct osf_dirent_callback {
struct dir_context ctx;
struct osf_dirent __user *dirent;
long __user *basep;
unsigned int count;
......@@ -146,17 +147,17 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
{
int error;
struct fd arg = fdget(fd);
struct osf_dirent_callback buf;
struct osf_dirent_callback buf = {
.ctx.actor = osf_filldir,
.dirent = dirent,
.basep = basep,
.count = count
};
if (!arg.file)
return -EBADF;
buf.dirent = dirent;
buf.basep = basep;
buf.count = count;
buf.error = 0;
error = vfs_readdir(arg.file, osf_filldir, &buf);
error = iterate_dir(arg.file, &buf.ctx);
if (error >= 0)
error = buf.error;
if (count != buf.count)
......
......@@ -26,7 +26,6 @@ static int hose_mmap_page_range(struct pci_controller *hose,
base = sparse ? hose->sparse_io_base : hose->dense_io_base;
vma->vm_pgoff += base >> PAGE_SHIFT;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
......
......@@ -394,9 +394,6 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
#define io_remap_pfn_range(vma, from, pfn, size, prot) \
remap_pfn_range(vma, from, pfn, size, prot)
#include <asm-generic/pgtable.h>
/* to cope with aliasing VIPT cache */
......
......@@ -79,8 +79,6 @@ extern unsigned int kobjsize(const void *objp);
* No page table caches to initialise.
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range remap_pfn_range
/*
* All 32bit addresses are effectively valid for vmalloc...
......
......@@ -318,13 +318,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define HAVE_ARCH_UNMAPPED_AREA
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
#define pgtable_cache_init() do { } while (0)
#endif /* !__ASSEMBLY__ */
......
......@@ -320,13 +320,6 @@ extern int kern_addr_valid(unsigned long addr);
#include <asm-generic/pgtable.h>
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
#define pgtable_cache_init() do { } while (0)
#endif /* !__ASSEMBLY__ */
......
......@@ -362,9 +362,6 @@ typedef pte_t *pte_addr_t;
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/* No page table caches to initialize (?) */
#define pgtable_cache_init() do { } while(0)
......
......@@ -88,7 +88,6 @@ extern char empty_zero_page[];
* No page table caches to initialise.
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range remap_pfn_range
/*
* All 32bit addresses are effectively valid for vmalloc...
......
......@@ -71,7 +71,6 @@ extern unsigned long empty_zero_page;
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range remap_pfn_range
#include <asm-generic/pgtable.h>
......
......@@ -258,9 +258,6 @@ static inline pgd_t * pgd_offset(const struct mm_struct *mm, unsigned long addre
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */
......
......@@ -488,9 +488,6 @@ static inline int pte_file(pte_t pte)
#define PageSkip(page) (0)
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
......
......@@ -52,9 +52,6 @@ extern int is_in_rom(unsigned long);
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
......
......@@ -452,10 +452,6 @@ static inline int pte_exec(pte_t pte)
#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
/* Nothing special about IO remapping at this point */
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/* I think this is in case we have page table caches; needed by init/main.c */
#define pgtable_cache_init() do { } while (0)
......
......@@ -493,9 +493,6 @@ extern void paging_init (void);
#define pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3)
#define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE })
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
......
......@@ -347,9 +347,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
......
......@@ -135,9 +135,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/* MMU-specific headers */
#ifdef CONFIG_SUN3
......
......@@ -55,9 +55,6 @@ extern unsigned int kobjsize(const void *objp);
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
......
......@@ -333,9 +333,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/*
* No page table caches to initialise
*/
......
......@@ -13,9 +13,6 @@
#include <asm/setup.h>
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#ifndef __ASSEMBLY__
extern int mem_init_done;
#endif
......
......@@ -394,9 +394,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
phys_t phys_addr_high = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot);
}
#else
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define io_remap_pfn_range io_remap_pfn_range
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
......
......@@ -486,9 +486,6 @@ extern void update_mmu_cache(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range((vma), (vaddr), (pfn), (size), (prot))
#define MK_IOSPACE_PFN(space, pfn) (pfn)
#define GET_IOSPACE(pfn) 0
#define GET_PFN(pfn) (pfn)
......
......@@ -221,7 +221,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* Leave vm_pgoff as-is, the PCI space address is the physical
* address on this platform.
*/
vma->vm_flags |= VM_LOCKED | VM_IO;
vma->vm_flags |= VM_LOCKED;
prot = pgprot_val(vma->vm_page_prot);
prot &= ~_PAGE_CACHE;
......
......@@ -446,9 +446,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#include <asm-generic/pgtable.h>
/*
......
......@@ -60,6 +60,7 @@ struct hpux_dirent {
};
struct getdents_callback {
struct dir_context ctx;
struct hpux_dirent __user *current_dir;
struct hpux_dirent __user *previous;
int count;
......@@ -110,24 +111,23 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
{
struct fd arg;
struct hpux_dirent __user * lastdirent;
struct getdents_callback buf;
struct getdents_callback buf = {
.ctx.actor = filldir,
.current_dir = dirent,
.count = count
};
int error;
arg = fdget(fd);
if (!arg.file)
return -EBADF;
buf.current_dir = dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
error = vfs_readdir(arg.file, filldir, &buf);
error = iterate_dir(arg.file, &buf.ctx);
if (error >= 0)
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
if (put_user(arg.file->f_pos, &lastdirent->d_off))
if (put_user(buf.ctx.pos, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count;
......
......@@ -506,9 +506,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#endif
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
/* We provide our own get_unmapped_area to provide cache coherency */
......
......@@ -198,9 +198,6 @@ extern void paging_init(void);
*/
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#include <asm-generic/pgtable.h>
......
......@@ -238,7 +238,7 @@ const struct file_operations spufs_context_fops = {
.release = spufs_dir_close,
.llseek = dcache_dir_lseek,
.read = generic_read_dir,
.readdir = dcache_readdir,
.iterate = dcache_readdir,
.fsync = noop_fsync,
};
EXPORT_SYMBOL_GPL(spufs_context_fops);
......
......@@ -58,9 +58,6 @@ extern unsigned long zero_page_mask;
#define __HAVE_COLOR_ZERO_PAGE
/* TODO: s390 cannot support io_remap_pfn_range... */
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif /* !__ASSEMBLY__ */
/*
......
......@@ -113,9 +113,6 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
#define pte_clear(mm, addr, xp) \
do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded
......
......@@ -124,9 +124,6 @@ typedef pte_t *pte_addr_t;
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
/*
......
......@@ -443,6 +443,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
}
#define io_remap_pfn_range io_remap_pfn_range
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
......
......@@ -914,6 +914,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
}
#define io_remap_pfn_range io_remap_pfn_range
#include <asm/tlbflush.h>
#include <asm-generic/pgtable.h>
......
......@@ -773,15 +773,6 @@ static int __pci_mmap_make_offset(struct pci_dev *pdev,
return 0;
}
/* Set vm_flags of VMA, as appropriate for this architecture, for a pci device
* mapping.
*/
static void __pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
}
/* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
* device mapping.
*/
......@@ -809,7 +800,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
if (ret < 0)
return ret;
__pci_mmap_set_flags(dev, vma, mmap_state);
__pci_mmap_set_pgprot(dev, vma, mmap_state);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
......
......@@ -362,9 +362,6 @@ do { \
#define kern_addr_valid(addr) (1)
#endif /* CONFIG_FLATMEM */
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
extern void vmalloc_sync_all(void);
#endif /* !__ASSEMBLY__ */
......
......@@ -69,8 +69,6 @@ extern unsigned long end_iomem;
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
#define io_remap_pfn_range remap_pfn_range
/*
* The i386 can't do page protection for execute, and considers that the same
* are read.
......
......@@ -303,13 +303,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
#include <asm-generic/pgtable.h>
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
#define io_remap_pfn_range(vma, from, pfn, size, prot) \
remap_pfn_range(vma, from, pfn, size, prot)
#define pgtable_cache_init() do { } while (0)
#endif /* !__ASSEMBLY__ */
......
......@@ -506,9 +506,6 @@ static inline unsigned long pages_to_mb(unsigned long npg)
return npg >> (20 - PAGE_SHIFT);
}
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#if PAGETABLE_LEVELS > 2
static inline int pud_none(pud_t pud)
{
......
......@@ -393,14 +393,6 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
extern void update_mmu_cache(struct vm_area_struct * vma,
unsigned long address, pte_t *ptep);
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
typedef pte_t *pte_addr_t;
#endif /* !defined (__ASSEMBLY__) */
......
......@@ -25,9 +25,9 @@
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/blkdev.h>
#include <linux/loop.h>
#include <linux/scatterlist.h>
#include <asm/uaccess.h>
#include "loop.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
......
......@@ -63,7 +63,6 @@
#include <linux/init.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/loop.h>
#include <linux/compat.h>
#include <linux/suspend.h>
#include <linux/freezer.h>
......@@ -76,6 +75,7 @@
#include <linux/sysfs.h>
#include <linux/miscdevice.h>
#include <linux/falloc.h>
#include "loop.h"
#include <asm/uaccess.h>
......
/*
* include/linux/loop.h
* loop.h
*
* Written by Theodore Ts'o, 3/29/93.
*
......
......@@ -617,7 +617,6 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
offset = drm_core_get_reg_ofs(dev);
vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma);
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
......
......@@ -97,7 +97,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
buf = dev_priv->mmap_buffer;
buf_priv = buf->dev_private;
vma->vm_flags |= (VM_IO | VM_DONTCOPY);
vma->vm_flags |= VM_DONTCOPY;
buf_priv->currently_mapped = I810_BUF_MAPPED;
......
......@@ -499,7 +499,6 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
}
vma->vm_private_data = vdev;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
......
......@@ -385,8 +385,6 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
vma->vm_flags |= VM_IO;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) {
......
......@@ -1258,13 +1258,9 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
vma->vm_flags |= VM_IO;
return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
return 0;
}
static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
......
......@@ -494,7 +494,6 @@ pxa3xx_gcu_misc_mmap(struct file *file, struct vm_area_struct *vma)
if (size != resource_size(priv->resource_mem))
return -EINVAL;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return io_remap_pfn_range(vma, vma->vm_start,
......
......@@ -101,16 +101,15 @@ static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
}
/**
* v9fs_dir_readdir - read a directory
* @filp: opened file structure
* @dirent: directory structure ???
* @filldir: function to populate directory structure ???
* v9fs_dir_readdir - iterate through a directory
* @file: opened file structure
* @ctx: actor we feed the entries to
*
*/
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
{
int over;
bool over;
struct p9_wstat st;
int err = 0;
struct p9_fid *fid;
......@@ -118,19 +117,19 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
int reclen = 0;
struct p9_rdir *rdir;
p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = filp->private_data;
p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
fid = file->private_data;
buflen = fid->clnt->msize - P9_IOHDRSZ;
rdir = v9fs_alloc_rdir_buf(filp, buflen);
rdir = v9fs_alloc_rdir_buf(file, buflen);
if (!rdir)
return -ENOMEM;
while (1) {
if (rdir->tail == rdir->head) {
err = v9fs_file_readn(filp, rdir->buf, NULL,
buflen, filp->f_pos);
err = v9fs_file_readn(file, rdir->buf, NULL,
buflen, ctx->pos);
if (err <= 0)
return err;
......@@ -148,51 +147,45 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
reclen = st.size+2;
over = filldir(dirent, st.name, strlen(st.name),
filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
over = !dir_emit(ctx, st.name, strlen(st.name),
v9fs_qid2ino(&st.qid), dt_type(&st));
p9stat_free(&st);
if (over)
return 0;
rdir->head += reclen;
filp->f_pos += reclen;
ctx->pos += reclen;
}
}
}
/**
* v9fs_dir_readdir_dotl - read a directory
* @filp: opened file structure
* @dirent: buffer to fill dirent structures
* @filldir: function to populate dirent structures
* v9fs_dir_readdir_dotl - iterate through a directory
* @file: opened file structure
* @ctx: actor we feed the entries to
*
*/
static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
filldir_t filldir)
static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
{
int over;
int err = 0;
struct p9_fid *fid;
int buflen;
struct p9_rdir *rdir;
struct p9_dirent curdirent;
u64 oldoffset = 0;
p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = filp->private_data;
p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
fid = file->private_data;
buflen = fid->clnt->msize - P9_READDIRHDRSZ;
rdir = v9fs_alloc_rdir_buf(filp, buflen);
rdir = v9fs_alloc_rdir_buf(file, buflen);
if (!rdir)
return -ENOMEM;
while (1) {
if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen,
filp->f_pos);
ctx->pos);
if (err <= 0)
return err;
......@@ -210,22 +203,13 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
return -EIO;
}
/* d_off in dirent structure tracks the offset into
* the next dirent in the dir. However, filldir()
* expects offset into the current dirent. Hence
* while calling filldir send the offset from the
* previous dirent structure.
*/
over = filldir(dirent, curdirent.d_name,
strlen(curdirent.d_name),
oldoffset, v9fs_qid2ino(&curdirent.qid),
curdirent.d_type);
oldoffset = curdirent.d_off;
if (over)
if (!dir_emit(ctx, curdirent.d_name,
strlen(curdirent.d_name),
v9fs_qid2ino(&curdirent.qid),
curdirent.d_type))
return 0;
filp->f_pos = curdirent.d_off;
ctx->pos = curdirent.d_off;
rdir->head += err;
}
}
......@@ -254,7 +238,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
const struct file_operations v9fs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir,
.iterate = v9fs_dir_readdir,
.open = v9fs_file_open,
.release = v9fs_dir_release,
};
......@@ -262,7 +246,7 @@ const struct file_operations v9fs_dir_operations = {
const struct file_operations v9fs_dir_operations_dotl = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = v9fs_dir_readdir_dotl,
.iterate = v9fs_dir_readdir_dotl,
.open = v9fs_file_open,
.release = v9fs_dir_release,
.fsync = v9fs_file_fsync_dotl,
......
......@@ -17,47 +17,43 @@
static DEFINE_RWLOCK(adfs_dir_lock);
static int
adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
adfs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct object_info obj;
struct adfs_dir dir;
int ret = 0;
if (filp->f_pos >> 32)
goto out;
if (ctx->pos >> 32)
return 0;
ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
if (ret)
goto out;
return ret;
switch ((unsigned long)filp->f_pos) {
case 0:
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
if (ctx->pos == 0) {
if (!dir_emit_dot(file, ctx))
goto free_out;
filp->f_pos += 1;
case 1:
if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
ctx->pos = 1;
}
if (ctx->pos == 1) {
if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
goto free_out;
filp->f_pos += 1;
default:
break;
ctx->pos = 2;
}
read_lock(&adfs_dir_lock);
ret = ops->setpos(&dir, filp->f_pos - 2);
ret = ops->setpos(&dir, ctx->pos - 2);
if (ret)
goto unlock_out;
while (ops->getnext(&dir, &obj) == 0) {
if (filldir(dirent, obj.name, obj.name_len,
filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
goto unlock_out;
filp->f_pos += 1;
if (!dir_emit(ctx, obj.name, obj.name_len,
obj.file_id, DT_UNKNOWN))
break;
ctx->pos++;
}
unlock_out:
......@@ -65,8 +61,6 @@ adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
free_out:
ops->free(&dir);
out:
return ret;
}
......@@ -192,7 +186,7 @@ adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_inf
const struct file_operations adfs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = adfs_readdir,
.iterate = adfs_readdir,
.fsync = generic_file_fsync,
};
......
......@@ -15,12 +15,12 @@
#include "affs.h"
static int affs_readdir(struct file *, void *, filldir_t);
static int affs_readdir(struct file *, struct dir_context *);
const struct file_operations affs_dir_operations = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
.readdir = affs_readdir,
.iterate = affs_readdir,
.fsync = affs_file_fsync,
};
......@@ -40,52 +40,35 @@ const struct inode_operations affs_dir_inode_operations = {
};
static int
affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
affs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
struct buffer_head *dir_bh;
struct buffer_head *fh_bh;
struct buffer_head *dir_bh = NULL;
struct buffer_head *fh_bh = NULL;
unsigned char *name;
int namelen;
u32 i;
int hash_pos;
int chain_pos;
u32 f_pos;
u32 ino;
int stored;
int res;
pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)ctx->pos);
stored = 0;
res = -EIO;
dir_bh = NULL;
fh_bh = NULL;
f_pos = filp->f_pos;
if (f_pos == 0) {
filp->private_data = (void *)0;
if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
if (ctx->pos < 2) {
file->private_data = (void *)0;
if (!dir_emit_dots(file, ctx))
return 0;
filp->f_pos = f_pos = 1;
stored++;
}
if (f_pos == 1) {
if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_path.dentry), DT_DIR) < 0)
return stored;
filp->f_pos = f_pos = 2;
stored++;
}
affs_lock_dir(inode);
chain_pos = (f_pos - 2) & 0xffff;
hash_pos = (f_pos - 2) >> 16;
chain_pos = (ctx->pos - 2) & 0xffff;
hash_pos = (ctx->pos - 2) >> 16;
if (chain_pos == 0xffff) {
affs_warning(sb, "readdir", "More than 65535 entries in chain");
chain_pos = 0;
hash_pos++;
filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
}
dir_bh = affs_bread(sb, inode->i_ino);
if (!dir_bh)
......@@ -94,8 +77,8 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* If the directory hasn't changed since the last call to readdir(),
* we can jump directly to where we left off.
*/
ino = (u32)(long)filp->private_data;
if (ino && filp->f_version == inode->i_version) {
ino = (u32)(long)file->private_data;
if (ino && file->f_version == inode->i_version) {
pr_debug("AFFS: readdir() left off=%d\n", ino);
goto inside;
}
......@@ -105,7 +88,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
fh_bh = affs_bread(sb, ino);
if (!fh_bh) {
affs_error(sb, "readdir","Cannot read block %d", i);
goto readdir_out;
return -EIO;
}
ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
affs_brelse(fh_bh);
......@@ -119,38 +102,34 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
if (!ino)
continue;
f_pos = (hash_pos << 16) + 2;
ctx->pos = (hash_pos << 16) + 2;
inside:
do {
fh_bh = affs_bread(sb, ino);
if (!fh_bh) {
affs_error(sb, "readdir","Cannot read block %d", ino);
goto readdir_done;
break;
}
namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
name = AFFS_TAIL(sb, fh_bh)->name + 1;
pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
namelen, name, ino, hash_pos, f_pos);
if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
namelen, name, ino, hash_pos, (u32)ctx->pos);
if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
goto readdir_done;
stored++;
f_pos++;
ctx->pos++;
ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
affs_brelse(fh_bh);
fh_bh = NULL;
} while (ino);
}
readdir_done:
filp->f_pos = f_pos;
filp->f_version = inode->i_version;
filp->private_data = (void *)(long)ino;
res = stored;
file->f_version = inode->i_version;
file->private_data = (void *)(long)ino;
readdir_out:
affs_brelse(dir_bh);
affs_brelse(fh_bh);
affs_unlock_dir(inode);
pr_debug("AFFS: readdir()=%d\n", stored);
return res;
return 0;
}
......@@ -22,7 +22,7 @@
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags);
static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
static int afs_readdir(struct file *file, struct dir_context *ctx);
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
static int afs_d_delete(const struct dentry *dentry);
static void afs_d_release(struct dentry *dentry);
......@@ -43,7 +43,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
.release = afs_release,
.readdir = afs_readdir,
.iterate = afs_readdir,
.lock = afs_lock,
.llseek = generic_file_llseek,
};
......@@ -119,9 +119,9 @@ struct afs_dir_page {
};
struct afs_lookup_cookie {
struct dir_context ctx;
struct afs_fid fid;
const char *name;
size_t nlen;
struct qstr name;
int found;
};
......@@ -228,20 +228,18 @@ static int afs_dir_open(struct inode *inode, struct file *file)
/*
* deal with one block in an AFS directory
*/
static int afs_dir_iterate_block(unsigned *fpos,
static int afs_dir_iterate_block(struct dir_context *ctx,
union afs_dir_block *block,
unsigned blkoff,
void *cookie,
filldir_t filldir)
unsigned blkoff)
{
union afs_dirent *dire;
unsigned offset, next, curr;
size_t nlen;
int tmp, ret;
int tmp;
_enter("%u,%x,%p,,",*fpos,blkoff,block);
_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
curr = (*fpos - blkoff) / sizeof(union afs_dirent);
curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);
/* walk through the block, an entry at a time */
for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
......@@ -256,7 +254,7 @@ static int afs_dir_iterate_block(unsigned *fpos,
_debug("ENT[%Zu.%u]: unused",
blkoff / sizeof(union afs_dir_block), offset);
if (offset >= curr)
*fpos = blkoff +
ctx->pos = blkoff +
next * sizeof(union afs_dirent);
continue;
}
......@@ -302,19 +300,15 @@ static int afs_dir_iterate_block(unsigned *fpos,
continue;
/* found the next entry */
ret = filldir(cookie,
dire->u.name,
nlen,
blkoff + offset * sizeof(union afs_dirent),
if (!dir_emit(ctx, dire->u.name, nlen,
ntohl(dire->u.vnode),
filldir == afs_lookup_filldir ?
ntohl(dire->u.unique) : DT_UNKNOWN);
if (ret < 0) {
ctx->actor == afs_lookup_filldir ?
ntohl(dire->u.unique) : DT_UNKNOWN)) {
_leave(" = 0 [full]");
return 0;
}
*fpos = blkoff + next * sizeof(union afs_dirent);
ctx->pos = blkoff + next * sizeof(union afs_dirent);
}
_leave(" = 1 [more]");
......@@ -324,8 +318,8 @@ static int afs_dir_iterate_block(unsigned *fpos,
/*
* iterate through the data blob that lists the contents of an AFS directory
*/
static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
filldir_t filldir, struct key *key)
static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
struct key *key)
{
union afs_dir_block *dblock;
struct afs_dir_page *dbuf;
......@@ -333,7 +327,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
unsigned blkoff, limit;
int ret;
_enter("{%lu},%u,,", dir->i_ino, *fpos);
_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
_leave(" = -ESTALE");
......@@ -341,13 +335,13 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
}
/* round the file position up to the next entry boundary */
*fpos += sizeof(union afs_dirent) - 1;
*fpos &= ~(sizeof(union afs_dirent) - 1);
ctx->pos += sizeof(union afs_dirent) - 1;
ctx->pos &= ~(sizeof(union afs_dirent) - 1);
/* walk through the blocks in sequence */
ret = 0;
while (*fpos < dir->i_size) {
blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1);
while (ctx->pos < dir->i_size) {
blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
/* fetch the appropriate page from the directory */
page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
......@@ -364,8 +358,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
do {
dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
sizeof(union afs_dir_block)];
ret = afs_dir_iterate_block(fpos, dblock, blkoff,
cookie, filldir);
ret = afs_dir_iterate_block(ctx, dblock, blkoff);
if (ret != 1) {
afs_dir_put_page(page);
goto out;
......@@ -373,7 +366,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
blkoff += sizeof(union afs_dir_block);
} while (*fpos < dir->i_size && blkoff < limit);
} while (ctx->pos < dir->i_size && blkoff < limit);
afs_dir_put_page(page);
ret = 0;
......@@ -387,23 +380,10 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
/*
* read an AFS directory
*/
static int afs_readdir(struct file *file, void *cookie, filldir_t filldir)
static int afs_readdir(struct file *file, struct dir_context *ctx)
{
unsigned fpos;
int ret;
_enter("{%Ld,{%lu}}",
file->f_pos, file_inode(file)->i_ino);
ASSERT(file->private_data != NULL);
fpos = file->f_pos;
ret = afs_dir_iterate(file_inode(file), &fpos,
cookie, filldir, file->private_data);
file->f_pos = fpos;
_leave(" = %d", ret);
return ret;
return afs_dir_iterate(file_inode(file),
ctx, file->private_data);
}
/*
......@@ -416,15 +396,16 @@ static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
{
struct afs_lookup_cookie *cookie = _cookie;
_enter("{%s,%Zu},%s,%u,,%llu,%u",
cookie->name, cookie->nlen, name, nlen,
_enter("{%s,%u},%s,%u,,%llu,%u",
cookie->name.name, cookie->name.len, name, nlen,
(unsigned long long) ino, dtype);
/* insanity checks first */
BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) {
if (cookie->name.len != nlen ||
memcmp(cookie->name.name, name, nlen) != 0) {
_leave(" = 0 [no]");
return 0;
}
......@@ -444,24 +425,18 @@ static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
struct afs_fid *fid, struct key *key)
{
struct afs_lookup_cookie cookie;
struct afs_super_info *as;
unsigned fpos;
struct afs_super_info *as = dir->i_sb->s_fs_info;
struct afs_lookup_cookie cookie = {
.ctx.actor = afs_lookup_filldir,
.name = dentry->d_name,
.fid.vid = as->volume->vid
};
int ret;
_enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name);
as = dir->i_sb->s_fs_info;
/* search the directory */
cookie.name = dentry->d_name.name;
cookie.nlen = dentry->d_name.len;
cookie.fid.vid = as->volume->vid;
cookie.found = 0;
fpos = 0;
ret = afs_dir_iterate(dir, &fpos, &cookie, afs_lookup_filldir,
key);
ret = afs_dir_iterate(dir, &cookie.ctx, key);
if (ret < 0) {
_leave(" = %d [iter]", ret);
return ret;
......
......@@ -41,7 +41,7 @@ const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.read = generic_read_dir,
.readdir = dcache_readdir,
.iterate = dcache_readdir,
.llseek = dcache_dir_lseek,
.unlocked_ioctl = autofs4_root_ioctl,
#ifdef CONFIG_COMPAT
......@@ -53,7 +53,7 @@ const struct file_operations autofs4_dir_operations = {
.open = autofs4_dir_open,
.release = dcache_dir_close,
.read = generic_read_dir,
.readdir = dcache_readdir,
.iterate = dcache_readdir,
.llseek = dcache_dir_lseek,
};
......
......@@ -45,7 +45,7 @@ static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return -EIO;
}
static int bad_file_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int bad_file_readdir(struct file *file, struct dir_context *ctx)
{
return -EIO;
}
......@@ -152,7 +152,7 @@ static const struct file_operations bad_file_ops =
.write = bad_file_write,
.aio_read = bad_file_aio_read,
.aio_write = bad_file_aio_write,
.readdir = bad_file_readdir,
.iterate = bad_file_readdir,
.poll = bad_file_poll,
.unlocked_ioctl = bad_file_unlocked_ioctl,
.compat_ioctl = bad_file_compat_ioctl,
......
......@@ -31,7 +31,7 @@ MODULE_LICENSE("GPL");
/* The units the vfs expects inode->i_blocks to be in */
#define VFS_BLOCK_SIZE 512
static int befs_readdir(struct file *, void *, filldir_t);
static int befs_readdir(struct file *, struct dir_context *);
static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
static int befs_readpage(struct file *file, struct page *page);
static sector_t befs_bmap(struct address_space *mapping, sector_t block);
......@@ -66,7 +66,7 @@ static struct kmem_cache *befs_inode_cachep;
static const struct file_operations befs_dir_operations = {
.read = generic_read_dir,
.readdir = befs_readdir,
.iterate = befs_readdir,
.llseek = generic_file_llseek,
};
......@@ -211,9 +211,9 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
}
static int
befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
befs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
befs_off_t value;
......@@ -221,15 +221,14 @@ befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
size_t keysize;
unsigned char d_type;
char keybuf[BEFS_NAME_LEN + 1];
char *nlsname;
int nlsnamelen;
const char *dirname = filp->f_path.dentry->d_name.name;
const char *dirname = file->f_path.dentry->d_name.name;
befs_debug(sb, "---> befs_readdir() "
"name %s, inode %ld, filp->f_pos %Ld",
dirname, inode->i_ino, filp->f_pos);
"name %s, inode %ld, ctx->pos %Ld",
dirname, inode->i_ino, ctx->pos);
result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1,
more:
result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1,
keybuf, &keysize, &value);
if (result == BEFS_ERR) {
......@@ -251,24 +250,29 @@ befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Convert to NLS */
if (BEFS_SB(sb)->nls) {
char *nlsname;
int nlsnamelen;
result =
befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
if (result < 0) {
befs_debug(sb, "<--- befs_readdir() ERROR");
return result;
}
result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos,
(ino_t) value, d_type);
if (!dir_emit(ctx, nlsname, nlsnamelen,
(ino_t) value, d_type)) {
kfree(nlsname);
return 0;
}
kfree(nlsname);
} else {
result = filldir(dirent, keybuf, keysize, filp->f_pos,
(ino_t) value, d_type);
if (!dir_emit(ctx, keybuf, keysize,
(ino_t) value, d_type))
return 0;
}
if (!result)
filp->f_pos++;
ctx->pos++;
goto more;
befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos);
befs_debug(sb, "<--- befs_readdir() pos %Ld", ctx->pos);
return 0;
}
......
......@@ -26,58 +26,51 @@ static struct buffer_head *bfs_find_entry(struct inode *dir,
const unsigned char *name, int namelen,
struct bfs_dirent **res_dir);
static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir)
static int bfs_readdir(struct file *f, struct dir_context *ctx)
{
struct inode *dir = file_inode(f);
struct buffer_head *bh;
struct bfs_dirent *de;
struct bfs_sb_info *info = BFS_SB(dir->i_sb);
unsigned int offset;
int block;
mutex_lock(&info->bfs_lock);
if (f->f_pos & (BFS_DIRENT_SIZE - 1)) {
if (ctx->pos & (BFS_DIRENT_SIZE - 1)) {
printf("Bad f_pos=%08lx for %s:%08lx\n",
(unsigned long)f->f_pos,
(unsigned long)ctx->pos,
dir->i_sb->s_id, dir->i_ino);
mutex_unlock(&info->bfs_lock);
return -EBADF;
return -EINVAL;
}
while (f->f_pos < dir->i_size) {
offset = f->f_pos & (BFS_BSIZE - 1);
block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS);
while (ctx->pos < dir->i_size) {
offset = ctx->pos & (BFS_BSIZE - 1);
block = BFS_I(dir)->i_sblock + (ctx->pos >> BFS_BSIZE_BITS);
bh = sb_bread(dir->i_sb, block);
if (!bh) {
f->f_pos += BFS_BSIZE - offset;
ctx->pos += BFS_BSIZE - offset;
continue;
}
do {
de = (struct bfs_dirent *)(bh->b_data + offset);
if (de->ino) {
int size = strnlen(de->name, BFS_NAMELEN);
if (filldir(dirent, de->name, size, f->f_pos,
if (!dir_emit(ctx, de->name, size,
le16_to_cpu(de->ino),
DT_UNKNOWN) < 0) {
DT_UNKNOWN)) {
brelse(bh);
mutex_unlock(&info->bfs_lock);
return 0;
}
}
offset += BFS_DIRENT_SIZE;
f->f_pos += BFS_DIRENT_SIZE;
} while ((offset < BFS_BSIZE) && (f->f_pos < dir->i_size));
ctx->pos += BFS_DIRENT_SIZE;
} while ((offset < BFS_BSIZE) && (ctx->pos < dir->i_size));
brelse(bh);
}
mutex_unlock(&info->bfs_lock);
return 0;
return 0;
}
const struct file_operations bfs_dir_operations = {
.read = generic_read_dir,
.readdir = bfs_readdir,
.iterate = bfs_readdir,
.fsync = generic_file_fsync,
.llseek = generic_file_llseek,
};
......
......@@ -1681,8 +1681,7 @@ int btrfs_should_delete_dir_index(struct list_head *del_list,
* btrfs_readdir_delayed_dir_index - read dir info stored in the delayed tree
*
*/
int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
filldir_t filldir,
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
struct list_head *ins_list)
{
struct btrfs_dir_item *di;
......@@ -1704,13 +1703,13 @@ int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
list_for_each_entry_safe(curr, next, ins_list, readdir_list) {
list_del(&curr->readdir_list);
if (curr->key.offset < filp->f_pos) {
if (curr->key.offset < ctx->pos) {
if (atomic_dec_and_test(&curr->refs))
kfree(curr);
continue;
}
filp->f_pos = curr->key.offset;
ctx->pos = curr->key.offset;
di = (struct btrfs_dir_item *)curr->data;
name = (char *)(di + 1);
......@@ -1719,7 +1718,7 @@ int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
d_type = btrfs_filetype_table[di->type];
btrfs_disk_key_to_cpu(&location, &di->location);
over = filldir(dirent, name, name_len, curr->key.offset,
over = !dir_emit(ctx, name, name_len,
location.objectid, d_type);
if (atomic_dec_and_test(&curr->refs))
......
......@@ -139,8 +139,7 @@ void btrfs_put_delayed_items(struct list_head *ins_list,
struct list_head *del_list);
int btrfs_should_delete_dir_index(struct list_head *del_list,
u64 index);
int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
filldir_t filldir,
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
struct list_head *ins_list);
/* for init */
......
......@@ -5137,10 +5137,9 @@ unsigned char btrfs_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
static int btrfs_real_readdir(struct file *filp, void *dirent,
filldir_t filldir)
static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_item *item;
struct btrfs_dir_item *di;
......@@ -5161,29 +5160,15 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
char tmp_name[32];
char *name_ptr;
int name_len;
int is_curr = 0; /* filp->f_pos points to the current index? */
int is_curr = 0; /* ctx->pos points to the current index? */
/* FIXME, use a real flag for deciding about the key type */
if (root->fs_info->tree_root == root)
key_type = BTRFS_DIR_ITEM_KEY;
/* special case for "." */
if (filp->f_pos == 0) {
over = filldir(dirent, ".", 1,
filp->f_pos, btrfs_ino(inode), DT_DIR);
if (over)
return 0;
filp->f_pos = 1;
}
/* special case for .., just use the back ref */
if (filp->f_pos == 1) {
u64 pino = parent_ino(filp->f_path.dentry);
over = filldir(dirent, "..", 2,
filp->f_pos, pino, DT_DIR);
if (over)
return 0;
filp->f_pos = 2;
}
if (!dir_emit_dots(file, ctx))
return 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
......@@ -5197,7 +5182,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
}
btrfs_set_key_type(&key, key_type);
key.offset = filp->f_pos;
key.offset = ctx->pos;
key.objectid = btrfs_ino(inode);
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
......@@ -5223,14 +5208,14 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
break;
if (btrfs_key_type(&found_key) != key_type)
break;
if (found_key.offset < filp->f_pos)
if (found_key.offset < ctx->pos)
goto next;
if (key_type == BTRFS_DIR_INDEX_KEY &&
btrfs_should_delete_dir_index(&del_list,
found_key.offset))
goto next;
filp->f_pos = found_key.offset;
ctx->pos = found_key.offset;
is_curr = 1;
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
......@@ -5274,9 +5259,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
over = 0;
goto skip;
}
over = filldir(dirent, name_ptr, name_len,
found_key.offset, location.objectid,
d_type);
over = !dir_emit(ctx, name_ptr, name_len,
location.objectid, d_type);
skip:
if (name_ptr != tmp_name)
......@@ -5295,9 +5279,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
if (key_type == BTRFS_DIR_INDEX_KEY) {
if (is_curr)
filp->f_pos++;
ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
&ins_list);
ctx->pos++;
ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
if (ret)
goto nopos;
}
......@@ -5308,9 +5291,9 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
* 32-bit glibc will use getdents64, but then strtol -
* so the last number we can serve is this.
*/
filp->f_pos = 0x7fffffff;
ctx->pos = 0x7fffffff;
else
filp->f_pos++;
ctx->pos++;
nopos:
ret = 0;
err:
......@@ -8731,7 +8714,7 @@ static const struct inode_operations btrfs_dir_ro_inode_operations = {
static const struct file_operations btrfs_dir_file_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = btrfs_real_readdir,
.iterate = btrfs_real_readdir,
.unlocked_ioctl = btrfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = btrfs_ioctl,
......
......@@ -111,11 +111,10 @@ static unsigned fpos_off(loff_t p)
* defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
* the MDS if/when the directory is modified).
*/
static int __dcache_readdir(struct file *filp,
void *dirent, filldir_t filldir)
static int __dcache_readdir(struct file *file, struct dir_context *ctx)
{
struct ceph_file_info *fi = filp->private_data;
struct dentry *parent = filp->f_dentry;
struct ceph_file_info *fi = file->private_data;
struct dentry *parent = file->f_dentry;
struct inode *dir = parent->d_inode;
struct list_head *p;
struct dentry *dentry, *last;
......@@ -126,14 +125,14 @@ static int __dcache_readdir(struct file *filp,
last = fi->dentry;
fi->dentry = NULL;
dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,
dout("__dcache_readdir %p at %llu (last %p)\n", dir, ctx->pos,
last);
spin_lock(&parent->d_lock);
/* start at beginning? */
if (filp->f_pos == 2 || last == NULL ||
filp->f_pos < ceph_dentry(last)->offset) {
if (ctx->pos == 2 || last == NULL ||
ctx->pos < ceph_dentry(last)->offset) {
if (list_empty(&parent->d_subdirs))
goto out_unlock;
p = parent->d_subdirs.prev;
......@@ -157,11 +156,11 @@ static int __dcache_readdir(struct file *filp,
if (!d_unhashed(dentry) && dentry->d_inode &&
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
filp->f_pos <= di->offset)
ctx->pos <= di->offset)
break;
dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
dentry->d_name.len, dentry->d_name.name, di->offset,
filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
ctx->pos, d_unhashed(dentry) ? " unhashed" : "",
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
......@@ -173,29 +172,27 @@ static int __dcache_readdir(struct file *filp,
spin_unlock(&dentry->d_lock);
spin_unlock(&parent->d_lock);
dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, ctx->pos,
dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
filp->f_pos = di->offset;
err = filldir(dirent, dentry->d_name.name,
dentry->d_name.len, di->offset,
ctx->pos = di->offset;
if (!dir_emit(ctx, dentry->d_name.name,
dentry->d_name.len,
ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
dentry->d_inode->i_mode >> 12);
if (last) {
if (err < 0) {
dentry->d_inode->i_mode >> 12)) {
if (last) {
/* remember our position */
fi->dentry = last;
fi->next_offset = di->offset;
} else {
dput(last);
}
dput(dentry);
return 0;
}
last = dentry;
if (err < 0)
goto out;
if (last)
dput(last);
last = dentry;
filp->f_pos++;
ctx->pos++;
/* make sure a dentry wasn't dropped while we didn't have parent lock */
if (!ceph_dir_is_complete(dir)) {
......@@ -235,59 +232,59 @@ static int note_last_dentry(struct ceph_file_info *fi, const char *name,
return 0;
}
static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int ceph_readdir(struct file *file, struct dir_context *ctx)
{
struct ceph_file_info *fi = filp->private_data;
struct inode *inode = file_inode(filp);
struct ceph_file_info *fi = file->private_data;
struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
struct ceph_mds_client *mdsc = fsc->mdsc;
unsigned frag = fpos_frag(filp->f_pos);
int off = fpos_off(filp->f_pos);
unsigned frag = fpos_frag(ctx->pos);
int off = fpos_off(ctx->pos);
int err;
u32 ftype;
struct ceph_mds_reply_info_parsed *rinfo;
const int max_entries = fsc->mount_options->max_readdir;
const int max_bytes = fsc->mount_options->max_readdir_bytes;
dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
dout("readdir %p file %p frag %u off %u\n", inode, file, frag, off);
if (fi->flags & CEPH_F_ATEND)
return 0;
/* always start with . and .. */
if (filp->f_pos == 0) {
if (ctx->pos == 0) {
/* note dir version at start of readdir so we can tell
* if any dentries get dropped */
fi->dir_release_count = atomic_read(&ci->i_release_count);
dout("readdir off 0 -> '.'\n");
if (filldir(dirent, ".", 1, ceph_make_fpos(0, 0),
if (!dir_emit(ctx, ".", 1,
ceph_translate_ino(inode->i_sb, inode->i_ino),
inode->i_mode >> 12) < 0)
inode->i_mode >> 12))
return 0;
filp->f_pos = 1;
ctx->pos = 1;
off = 1;
}
if (filp->f_pos == 1) {
ino_t ino = parent_ino(filp->f_dentry);
if (ctx->pos == 1) {
ino_t ino = parent_ino(file->f_dentry);
dout("readdir off 1 -> '..'\n");
if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1),
if (!dir_emit(ctx, "..", 2,
ceph_translate_ino(inode->i_sb, ino),
inode->i_mode >> 12) < 0)
inode->i_mode >> 12))
return 0;
filp->f_pos = 2;
ctx->pos = 2;
off = 2;
}
/* can we use the dcache? */
spin_lock(&ci->i_ceph_lock);
if ((filp->f_pos == 2 || fi->dentry) &&
if ((ctx->pos == 2 || fi->dentry) &&
!ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
ceph_snap(inode) != CEPH_SNAPDIR &&
__ceph_dir_is_complete(ci) &&
__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
spin_unlock(&ci->i_ceph_lock);
err = __dcache_readdir(filp, dirent, filldir);
err = __dcache_readdir(file, ctx);
if (err != -EAGAIN)
return err;
} else {
......@@ -327,7 +324,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
return PTR_ERR(req);
req->r_inode = inode;
ihold(inode);
req->r_dentry = dget(filp->f_dentry);
req->r_dentry = dget(file->f_dentry);
/* hints to request -> mds selection code */
req->r_direct_mode = USE_AUTH_MDS;
req->r_direct_hash = ceph_frag_value(frag);
......@@ -379,15 +376,16 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
rinfo = &fi->last_readdir->r_reply_info;
dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
rinfo->dir_nr, off, fi->offset);
ctx->pos = ceph_make_fpos(frag, off);
while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
u64 pos = ceph_make_fpos(frag, off);
struct ceph_mds_reply_inode *in =
rinfo->dir_in[off - fi->offset].in;
struct ceph_vino vino;
ino_t ino;
dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
off, off - fi->offset, rinfo->dir_nr, pos,
off, off - fi->offset, rinfo->dir_nr, ctx->pos,
rinfo->dir_dname_len[off - fi->offset],
rinfo->dir_dname[off - fi->offset], in);
BUG_ON(!in);
......@@ -395,16 +393,15 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
vino.ino = le64_to_cpu(in->ino);
vino.snap = le64_to_cpu(in->snapid);
ino = ceph_vino_to_ino(vino);
if (filldir(dirent,
if (!dir_emit(ctx,
rinfo->dir_dname[off - fi->offset],
rinfo->dir_dname_len[off - fi->offset],
pos,
ceph_translate_ino(inode->i_sb, ino), ftype) < 0) {
ceph_translate_ino(inode->i_sb, ino), ftype)) {
dout("filldir stopping us...\n");
return 0;
}
off++;
filp->f_pos = pos + 1;
ctx->pos++;
}
if (fi->last_name) {
......@@ -417,7 +414,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!ceph_frag_is_rightmost(frag)) {
frag = ceph_frag_next(frag);
off = 0;
filp->f_pos = ceph_make_fpos(frag, off);
ctx->pos = ceph_make_fpos(frag, off);
dout("readdir next frag is %x\n", frag);
goto more;
}
......@@ -432,11 +429,11 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
dout(" marking %p complete\n", inode);
__ceph_dir_set_complete(ci, fi->dir_release_count);
ci->i_max_offset = filp->f_pos;
ci->i_max_offset = ctx->pos;
}
spin_unlock(&ci->i_ceph_lock);
dout("readdir %p filp %p done.\n", inode, filp);
dout("readdir %p file %p done.\n", inode, file);
return 0;
}
......@@ -1268,7 +1265,7 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
const struct file_operations ceph_dir_fops = {
.read = ceph_read_dir,
.readdir = ceph_readdir,
.iterate = ceph_readdir,
.llseek = ceph_dir_llseek,
.open = ceph_open,
.release = ceph_release,
......
......@@ -968,7 +968,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
};
const struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
.iterate = cifs_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
.unlocked_ioctl = cifs_ioctl,
......
......@@ -101,7 +101,7 @@ extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
extern int cifs_readdir(struct file *file, struct dir_context *ctx);
/* Functions related to dir entries */
extern const struct dentry_operations cifs_dentry_ops;
......
......@@ -537,14 +537,14 @@ static int cifs_save_resume_key(const char *current_entry,
* every entry (do not increment for . or .. entry).
*/
static int
find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
struct file *file, char **current_entry, int *num_to_ret)
{
__u16 search_flags;
int rc = 0;
int pos_in_buf = 0;
loff_t first_entry_in_buffer;
loff_t index_to_find = file->f_pos;
loff_t index_to_find = pos;
struct cifsFileInfo *cfile = file->private_data;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct TCP_Server_Info *server = tcon->ses->server;
......@@ -659,8 +659,9 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
void *dirent, char *scratch_buf, unsigned int max_len)
static int cifs_filldir(char *find_entry, struct file *file,
struct dir_context *ctx,
char *scratch_buf, unsigned int max_len)
{
struct cifsFileInfo *file_info = file->private_data;
struct super_block *sb = file->f_path.dentry->d_sb;
......@@ -740,13 +741,11 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
cifs_prime_dcache(file->f_dentry, &name, &fattr);
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
rc = filldir(dirent, name.name, name.len, file->f_pos, ino,
fattr.cf_dtype);
return rc;
return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
}
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
int cifs_readdir(struct file *file, struct dir_context *ctx)
{
int rc = 0;
unsigned int xid;
......@@ -772,103 +771,86 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
goto rddir2_exit;
}
switch ((int) file->f_pos) {
case 0:
if (filldir(direntry, ".", 1, file->f_pos,
file_inode(file)->i_ino, DT_DIR) < 0) {
cifs_dbg(VFS, "Filldir for current dir failed\n");
rc = -ENOMEM;
break;
}
file->f_pos++;
case 1:
if (filldir(direntry, "..", 2, file->f_pos,
parent_ino(file->f_path.dentry), DT_DIR) < 0) {
cifs_dbg(VFS, "Filldir for parent dir failed\n");
rc = -ENOMEM;
break;
}
file->f_pos++;
default:
/* 1) If search is active,
is in current search buffer?
if it before then restart search
if after then keep searching till find it */
if (file->private_data == NULL) {
rc = -EINVAL;
free_xid(xid);
return rc;
}
cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) {
if (cifsFile->srch_inf.emptyDir) {
cifs_dbg(FYI, "End of search, empty dir\n");
rc = 0;
break;
}
} /* else {
cifsFile->invalidHandle = true;
tcon->ses->server->close(xid, tcon, &cifsFile->fid);
} */
if (!dir_emit_dots(file, ctx))
goto rddir2_exit;
tcon = tlink_tcon(cifsFile->tlink);
rc = find_cifs_entry(xid, tcon, file, &current_entry,
&num_to_fill);
if (rc) {
cifs_dbg(FYI, "fce error %d\n", rc);
goto rddir2_exit;
} else if (current_entry != NULL) {
cifs_dbg(FYI, "entry %lld found\n", file->f_pos);
} else {
cifs_dbg(FYI, "could not find entry\n");
/* 1) If search is active,
is in current search buffer?
if it before then restart search
if after then keep searching till find it */
if (file->private_data == NULL) {
rc = -EINVAL;
goto rddir2_exit;
}
cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) {
if (cifsFile->srch_inf.emptyDir) {
cifs_dbg(FYI, "End of search, empty dir\n");
rc = 0;
goto rddir2_exit;
}
cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
max_len = tcon->ses->server->ops->calc_smb_size(
cifsFile->srch_inf.ntwrk_buf_start);
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
if (tmp_buf == NULL) {
rc = -ENOMEM;
} /* else {
cifsFile->invalidHandle = true;
tcon->ses->server->close(xid, tcon, &cifsFile->fid);
} */
tcon = tlink_tcon(cifsFile->tlink);
rc = find_cifs_entry(xid, tcon, ctx->pos, file, &current_entry,
&num_to_fill);
if (rc) {
cifs_dbg(FYI, "fce error %d\n", rc);
goto rddir2_exit;
} else if (current_entry != NULL) {
cifs_dbg(FYI, "entry %lld found\n", ctx->pos);
} else {
cifs_dbg(FYI, "could not find entry\n");
goto rddir2_exit;
}
cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
max_len = tcon->ses->server->ops->calc_smb_size(
cifsFile->srch_inf.ntwrk_buf_start);
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
if (tmp_buf == NULL) {
rc = -ENOMEM;
goto rddir2_exit;
}
for (i = 0; i < num_to_fill; i++) {
if (current_entry == NULL) {
/* evaluate whether this case is an error */
cifs_dbg(VFS, "past SMB end, num to fill %d i %d\n",
num_to_fill, i);
break;
}
for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
if (current_entry == NULL) {
/* evaluate whether this case is an error */
cifs_dbg(VFS, "past SMB end, num to fill %d i %d\n",
num_to_fill, i);
break;
}
/*
* if buggy server returns . and .. late do we want to
* check for that here?
*/
rc = cifs_filldir(current_entry, file, filldir,
direntry, tmp_buf, max_len);
if (rc == -EOVERFLOW) {
/*
* if buggy server returns . and .. late do we want to
* check for that here?
*/
rc = cifs_filldir(current_entry, file, ctx,
tmp_buf, max_len);
if (rc) {
if (rc > 0)
rc = 0;
break;
}
file->f_pos++;
if (file->f_pos ==
cifsFile->srch_inf.index_of_last_entry) {
cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
file->f_pos, tmp_buf);
cifs_save_resume_key(current_entry, cifsFile);
break;
} else
current_entry =
nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
break;
}
kfree(tmp_buf);
break;
} /* end switch */
ctx->pos++;
if (ctx->pos ==
cifsFile->srch_inf.index_of_last_entry) {
cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
ctx->pos, tmp_buf);
cifs_save_resume_key(current_entry, cifsFile);
break;
} else
current_entry =
nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
}
kfree(tmp_buf);
rddir2_exit:
free_xid(xid);
......
......@@ -43,15 +43,14 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry);
/* dir file-ops */
static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
static int coda_readdir(struct file *file, struct dir_context *ctx);
/* dentry ops */
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
static int coda_dentry_delete(const struct dentry *);
/* support routines */
static int coda_venus_readdir(struct file *coda_file, void *buf,
filldir_t filldir);
static int coda_venus_readdir(struct file *, struct dir_context *);
/* same as fs/bad_inode.c */
static int coda_return_EIO(void)
......@@ -85,7 +84,7 @@ const struct inode_operations coda_dir_inode_operations =
const struct file_operations coda_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = coda_readdir,
.iterate = coda_readdir,
.open = coda_open,
.release = coda_release,
.fsync = coda_fsync,
......@@ -378,7 +377,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
/* file operations for directories */
static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
{
struct coda_file_info *cfi;
struct file *host_file;
......@@ -391,30 +390,19 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
if (!host_file->f_op)
return -ENOTDIR;
if (host_file->f_op->readdir)
{
/* potemkin case: we were handed a directory inode.
* We can't use vfs_readdir because we have to keep the file
* position in sync between the coda_file and the host_file.
* and as such we need grab the inode mutex. */
if (host_file->f_op->iterate) {
struct inode *host_inode = file_inode(host_file);
mutex_lock(&host_inode->i_mutex);
host_file->f_pos = coda_file->f_pos;
ret = -ENOENT;
if (!IS_DEADDIR(host_inode)) {
ret = host_file->f_op->readdir(host_file, buf, filldir);
ret = host_file->f_op->iterate(host_file, ctx);
file_accessed(host_file);
}
coda_file->f_pos = host_file->f_pos;
mutex_unlock(&host_inode->i_mutex);
return ret;
}
else /* Venus: we must read Venus dirents from a file */
ret = coda_venus_readdir(coda_file, buf, filldir);
return ret;
/* Venus: we must read Venus dirents from a file */
return coda_venus_readdir(coda_file, ctx);
}
static inline unsigned int CDT2DT(unsigned char cdt)
......@@ -437,10 +425,8 @@ static inline unsigned int CDT2DT(unsigned char cdt)
}
/* support routines */
static int coda_venus_readdir(struct file *coda_file, void *buf,
filldir_t filldir)
static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
{
int result = 0; /* # of entries returned */
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct file *host_file;
......@@ -462,23 +448,12 @@ static int coda_venus_readdir(struct file *coda_file, void *buf,
vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
if (!vdir) return -ENOMEM;
if (coda_file->f_pos == 0) {
ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
if (ret < 0)
goto out;
result++;
coda_file->f_pos++;
}
if (coda_file->f_pos == 1) {
ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR);
if (ret < 0)
goto out;
result++;
coda_file->f_pos++;
}
if (!dir_emit_dots(coda_file, ctx))
goto out;
while (1) {
/* read entries from the directory file */
ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
ret = kernel_read(host_file, ctx->pos - 2, (char *)vdir,
sizeof(*vdir));
if (ret < 0) {
printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
......@@ -507,7 +482,7 @@ static int coda_venus_readdir(struct file *coda_file, void *buf,
/* Make sure we skip '.' and '..', we already got those */
if (name.name[0] == '.' && (name.len == 1 ||
(vdir->d_name[1] == '.' && name.len == 2)))
(name.name[1] == '.' && name.len == 2)))
vdir->d_fileno = name.len = 0;
/* skip null entries */
......@@ -520,19 +495,16 @@ static int coda_venus_readdir(struct file *coda_file, void *buf,
if (!ino) ino = vdir->d_fileno;
type = CDT2DT(vdir->d_type);
ret = filldir(buf, name.name, name.len,
coda_file->f_pos, ino, type);
/* failure means no space for filling in this round */
if (ret < 0) break;
result++;
if (!dir_emit(ctx, name.name, name.len, ino, type))
break;
}
/* we'll always have progress because d_reclen is unsigned and
* we've already established it is non-zero. */
coda_file->f_pos += vdir->d_reclen;
ctx->pos += vdir->d_reclen;
}
out:
kfree(vdir);
return result ? result : ret;
return 0;
}
/* called when a cache lookup succeeds */
......
......@@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
};
struct compat_readdir_callback {
struct dir_context ctx;
struct compat_old_linux_dirent __user *dirent;
int result;
};
......@@ -873,15 +874,15 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
{
int error;
struct fd f = fdget(fd);
struct compat_readdir_callback buf;
struct compat_readdir_callback buf = {
.ctx.actor = compat_fillonedir,
.dirent = dirent
};
if (!f.file)
return -EBADF;
buf.result = 0;
buf.dirent = dirent;
error = vfs_readdir(f.file, compat_fillonedir, &buf);
error = iterate_dir(f.file, &buf.ctx);
if (buf.result)
error = buf.result;
......@@ -897,6 +898,7 @@ struct compat_linux_dirent {
};
struct compat_getdents_callback {
struct dir_context ctx;
struct compat_linux_dirent __user *current_dir;
struct compat_linux_dirent __user *previous;
int count;
......@@ -951,7 +953,11 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
{
struct fd f;
struct compat_linux_dirent __user * lastdirent;
struct compat_getdents_callback buf;
struct compat_getdents_callback buf = {
.ctx.actor = compat_filldir,
.current_dir = dirent,
.count = count
};
int error;
if (!access_ok(VERIFY_WRITE, dirent, count))
......@@ -961,17 +967,12 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
if (!f.file)
return -EBADF;
buf.current_dir = dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
error = vfs_readdir(f.file, compat_filldir, &buf);
error = iterate_dir(f.file, &buf.ctx);
if (error >= 0)
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
if (put_user(f.file->f_pos, &lastdirent->d_off))
if (put_user(buf.ctx.pos, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count;
......@@ -983,6 +984,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
struct compat_getdents_callback64 {
struct dir_context ctx;
struct linux_dirent64 __user *current_dir;
struct linux_dirent64 __user *previous;
int count;
......@@ -1036,7 +1038,11 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
{
struct fd f;
struct linux_dirent64 __user * lastdirent;
struct compat_getdents_callback64 buf;
struct compat_getdents_callback64 buf = {
.ctx.actor = compat_filldir64,
.current_dir = dirent,
.count = count
};
int error;
if (!access_ok(VERIFY_WRITE, dirent, count))
......@@ -1046,17 +1052,12 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
if (!f.file)
return -EBADF;
buf.current_dir = dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
error = vfs_readdir(f.file, compat_filldir64, &buf);
error = iterate_dir(f.file, &buf.ctx);
if (error >= 0)
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
typeof(lastdirent->d_off) d_off = f.file->f_pos;
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
if (__put_user_unaligned(d_off, &lastdirent->d_off))
error = -EFAULT;
else
......
......@@ -66,7 +66,6 @@
#include <linux/gigaset_dev.h>
#ifdef CONFIG_BLOCK
#include <linux/loop.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
#include <scsi/scsi.h>
......@@ -954,8 +953,6 @@ COMPATIBLE_IOCTL(MTIOCTOP)
/* Socket level stuff */
COMPATIBLE_IOCTL(FIOQSIZE)
#ifdef CONFIG_BLOCK
/* loop */
IGNORE_IOCTL(LOOP_CLR_FD)
/* md calls this on random blockdevs */
IGNORE_IOCTL(RAID_VERSION)
/* qemu/qemu-img might call these two on plain files for probing */
......
......@@ -1532,84 +1532,66 @@ static inline unsigned char dt_type(struct configfs_dirent *sd)
return (sd->s_mode >> 12) & 15;
}
static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
static int configfs_readdir(struct file *file, struct dir_context *ctx)
{
struct dentry *dentry = filp->f_path.dentry;
struct dentry *dentry = file->f_path.dentry;
struct super_block *sb = dentry->d_sb;
struct configfs_dirent * parent_sd = dentry->d_fsdata;
struct configfs_dirent *cursor = filp->private_data;
struct configfs_dirent *cursor = file->private_data;
struct list_head *p, *q = &cursor->s_sibling;
ino_t ino = 0;
int i = filp->f_pos;
switch (i) {
case 0:
ino = dentry->d_inode->i_ino;
if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
break;
filp->f_pos++;
i++;
/* fallthrough */
case 1:
ino = parent_ino(dentry);
if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
break;
filp->f_pos++;
i++;
/* fallthrough */
default:
if (filp->f_pos == 2) {
spin_lock(&configfs_dirent_lock);
list_move(q, &parent_sd->s_children);
spin_unlock(&configfs_dirent_lock);
}
for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
struct configfs_dirent *next;
const char * name;
int len;
struct inode *inode = NULL;
if (!dir_emit_dots(file, ctx))
return 0;
if (ctx->pos == 2) {
spin_lock(&configfs_dirent_lock);
list_move(q, &parent_sd->s_children);
spin_unlock(&configfs_dirent_lock);
}
for (p = q->next; p != &parent_sd->s_children; p = p->next) {
struct configfs_dirent *next;
const char *name;
int len;
struct inode *inode = NULL;
next = list_entry(p, struct configfs_dirent, s_sibling);
if (!next->s_element)
continue;
next = list_entry(p, struct configfs_dirent,
s_sibling);
if (!next->s_element)
continue;
name = configfs_get_name(next);
len = strlen(name);
/*
* We'll have a dentry and an inode for
* PINNED items and for open attribute
* files. We lock here to prevent a race
* with configfs_d_iput() clearing
* s_dentry before calling iput().
*
* Why do we go to the trouble? If
* someone has an attribute file open,
* the inode number should match until
* they close it. Beyond that, we don't
* care.
*/
spin_lock(&configfs_dirent_lock);
dentry = next->s_dentry;
if (dentry)
inode = dentry->d_inode;
if (inode)
ino = inode->i_ino;
spin_unlock(&configfs_dirent_lock);
if (!inode)
ino = iunique(sb, 2);
name = configfs_get_name(next);
len = strlen(name);
/*
* We'll have a dentry and an inode for
* PINNED items and for open attribute
* files. We lock here to prevent a race
* with configfs_d_iput() clearing
* s_dentry before calling iput().
*
* Why do we go to the trouble? If
* someone has an attribute file open,
* the inode number should match until
* they close it. Beyond that, we don't
* care.
*/
spin_lock(&configfs_dirent_lock);
dentry = next->s_dentry;
if (dentry)
inode = dentry->d_inode;
if (inode)
ino = inode->i_ino;
spin_unlock(&configfs_dirent_lock);
if (!inode)
ino = iunique(sb, 2);
if (filldir(dirent, name, len, filp->f_pos, ino,
dt_type(next)) < 0)
return 0;
if (!dir_emit(ctx, name, len, ino, dt_type(next)))
return 0;
spin_lock(&configfs_dirent_lock);
list_move(q, p);
spin_unlock(&configfs_dirent_lock);
p = q;
filp->f_pos++;
}
spin_lock(&configfs_dirent_lock);
list_move(q, p);
spin_unlock(&configfs_dirent_lock);
p = q;
ctx->pos++;
}
return 0;
}
......@@ -1661,7 +1643,7 @@ const struct file_operations configfs_dir_operations = {
.release = configfs_dir_close,
.llseek = configfs_dir_lseek,
.read = generic_read_dir,
.readdir = configfs_readdir,
.iterate = configfs_readdir,
};
int configfs_register_subsystem(struct configfs_subsystem *subsys)
......
......@@ -349,18 +349,17 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
/*
* Read a cramfs directory entry.
*/
static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int cramfs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
char *buf;
unsigned int offset;
int copied;
/* Offset within the thing. */
offset = filp->f_pos;
if (offset >= inode->i_size)
if (ctx->pos >= inode->i_size)
return 0;
offset = ctx->pos;
/* Directory entries are always 4-byte aligned */
if (offset & 3)
return -EINVAL;
......@@ -369,14 +368,13 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!buf)
return -ENOMEM;
copied = 0;
while (offset < inode->i_size) {
struct cramfs_inode *de;
unsigned long nextoffset;
char *name;
ino_t ino;
umode_t mode;
int namelen, error;
int namelen;
mutex_lock(&read_mutex);
de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);
......@@ -402,13 +400,10 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
namelen--;
}
error = filldir(dirent, buf, namelen, offset, ino, mode >> 12);
if (error)
if (!dir_emit(ctx, buf, namelen, ino, mode >> 12))
break;
offset = nextoffset;
filp->f_pos = offset;
copied++;
ctx->pos = offset = nextoffset;
}
kfree(buf);
return 0;
......@@ -547,7 +542,7 @@ static const struct address_space_operations cramfs_aops = {
static const struct file_operations cramfs_directory_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = cramfs_readdir,
.iterate = cramfs_readdir,
};
static const struct inode_operations cramfs_dir_inode_operations = {
......
......@@ -68,9 +68,9 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
}
struct ecryptfs_getdents_callback {
void *dirent;
struct dir_context ctx;
struct dir_context *caller;
struct dentry *dentry;
filldir_t filldir;
int filldir_called;
int entries_written;
};
......@@ -96,9 +96,10 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
rc);
goto out;
}
rc = buf->filldir(buf->dirent, name, name_size, offset, ino, d_type);
buf->caller->pos = buf->ctx.pos;
rc = !dir_emit(buf->caller, name, name_size, ino, d_type);
kfree(name);
if (rc >= 0)
if (!rc)
buf->entries_written++;
out:
return rc;
......@@ -107,27 +108,23 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
/**
* ecryptfs_readdir
* @file: The eCryptfs directory file
* @dirent: Directory entry handle
* @filldir: The filldir callback function
* @ctx: The actor to feed the entries to
*/
static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
{
int rc;
struct file *lower_file;
struct inode *inode;
struct ecryptfs_getdents_callback buf;
struct ecryptfs_getdents_callback buf = {
.ctx.actor = ecryptfs_filldir,
.caller = ctx,
.dentry = file->f_path.dentry
};
lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = file->f_pos;
lower_file->f_pos = ctx->pos;
inode = file_inode(file);
memset(&buf, 0, sizeof(buf));
buf.dirent = dirent;
buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
buf.filldir_called = 0;
buf.entries_written = 0;
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
file->f_pos = lower_file->f_pos;
rc = iterate_dir(lower_file, &buf.ctx);
ctx->pos = buf.ctx.pos;
if (rc < 0)
goto out;
if (buf.filldir_called && !buf.entries_written)
......@@ -344,7 +341,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#endif
const struct file_operations ecryptfs_dir_fops = {
.readdir = ecryptfs_readdir,
.iterate = ecryptfs_readdir,
.read = generic_read_dir,
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
#ifdef CONFIG_COMPAT
......@@ -365,7 +362,7 @@ const struct file_operations ecryptfs_main_fops = {
.aio_read = ecryptfs_read_update_atime,
.write = do_sync_write,
.aio_write = generic_file_aio_write,
.readdir = ecryptfs_readdir,
.iterate = ecryptfs_readdir,
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ecryptfs_compat_ioctl,
......
......@@ -7,40 +7,38 @@
#include <linux/buffer_head.h>
#include "efs.h"
static int efs_readdir(struct file *, void *, filldir_t);
static int efs_readdir(struct file *, struct dir_context *);
const struct file_operations efs_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = efs_readdir,
.iterate = efs_readdir,
};
const struct inode_operations efs_dir_inode_operations = {
.lookup = efs_lookup,
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
struct inode *inode = file_inode(filp);
struct buffer_head *bh;
struct efs_dir *dirblock;
struct efs_dentry *dirslot;
efs_ino_t inodenum;
static int efs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
efs_block_t block;
int slot, namelen;
char *nameptr;
int slot;
if (inode->i_size & (EFS_DIRBSIZE-1))
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
/* work out where this entry can be found */
block = filp->f_pos >> EFS_DIRBSIZE_BITS;
block = ctx->pos >> EFS_DIRBSIZE_BITS;
/* each block contains at most 256 slots */
slot = filp->f_pos & 0xff;
slot = ctx->pos & 0xff;
/* look at all blocks */
while (block < inode->i_blocks) {
struct efs_dir *dirblock;
struct buffer_head *bh;
/* read the dir block */
bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
......@@ -57,11 +55,14 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
break;
}
while (slot < dirblock->slots) {
if (dirblock->space[slot] == 0) {
slot++;
for (; slot < dirblock->slots; slot++) {
struct efs_dentry *dirslot;
efs_ino_t inodenum;
const char *nameptr;
int namelen;
if (dirblock->space[slot] == 0)
continue;
}
dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
......@@ -72,39 +73,29 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
#ifdef DEBUG
printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen);
#endif
if (namelen > 0) {
/* found the next entry */
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
/* copy filename and data in dirslot */
filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN);
/* sanity check */
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
slot++;
continue;
}
/* store position of next slot */
if (++slot == dirblock->slots) {
slot = 0;
block++;
}
if (!namelen)
continue;
/* found the next entry */
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
/* sanity check */
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
continue;
}
/* copy filename and data in dirslot */
if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) {
brelse(bh);
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
goto out;
return 0;
}
slot++;
}
brelse(bh);
slot = 0;
block++;
}
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
out:
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
return 0;
}
......@@ -239,22 +239,19 @@ void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode)
}
static int
exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
exofs_readdir(struct file *file, struct dir_context *ctx)
{
loff_t pos = filp->f_pos;
struct inode *inode = file_inode(filp);
loff_t pos = ctx->pos;
struct inode *inode = file_inode(file);
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
unsigned long npages = dir_pages(inode);
unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
unsigned char *types = NULL;
int need_revalidate = (filp->f_version != inode->i_version);
int need_revalidate = (file->f_version != inode->i_version);
if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
return 0;
types = exofs_filetype_table;
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
struct exofs_dir_entry *de;
......@@ -263,7 +260,7 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (IS_ERR(page)) {
EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
inode->i_ino);
filp->f_pos += PAGE_CACHE_SIZE - offset;
ctx->pos += PAGE_CACHE_SIZE - offset;
return PTR_ERR(page);
}
kaddr = page_address(page);
......@@ -271,9 +268,9 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (offset) {
offset = exofs_validate_entry(kaddr, offset,
chunk_mask);
filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
ctx->pos = (n<<PAGE_CACHE_SHIFT) + offset;
}
filp->f_version = inode->i_version;
file->f_version = inode->i_version;
need_revalidate = 0;
}
de = (struct exofs_dir_entry *)(kaddr + offset);
......@@ -288,27 +285,24 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
return -EIO;
}
if (de->inode_no) {
int over;
unsigned char d_type = DT_UNKNOWN;
unsigned char t;
if (types && de->file_type < EXOFS_FT_MAX)
d_type = types[de->file_type];
if (de->file_type < EXOFS_FT_MAX)
t = exofs_filetype_table[de->file_type];
else
t = DT_UNKNOWN;
offset = (char *)de - kaddr;
over = filldir(dirent, de->name, de->name_len,
(n<<PAGE_CACHE_SHIFT) | offset,
if (!dir_emit(ctx, de->name, de->name_len,
le64_to_cpu(de->inode_no),
d_type);
if (over) {
t)) {
exofs_put_page(page);
return 0;
}
}
filp->f_pos += le16_to_cpu(de->rec_len);
ctx->pos += le16_to_cpu(de->rec_len);
}
exofs_put_page(page);
}
return 0;
}
......@@ -669,5 +663,5 @@ int exofs_empty_dir(struct inode *inode)
const struct file_operations exofs_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = exofs_readdir,
.iterate = exofs_readdir,
};
......@@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
}
struct getdents_callback {
struct dir_context ctx;
char *name; /* name that was found. It already points to a
buffer NAME_MAX+1 is size */
unsigned long ino; /* the inum we are looking for */
......@@ -254,7 +255,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
struct inode *dir = path->dentry->d_inode;
int error;
struct file *file;
struct getdents_callback buffer;
struct getdents_callback buffer = {
.ctx.actor = filldir_one,
.name = name,
.ino = child->d_inode->i_ino
};
error = -ENOTDIR;
if (!dir || !S_ISDIR(dir->i_mode))
......@@ -271,17 +276,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
goto out;
error = -EINVAL;
if (!file->f_op->readdir)
if (!file->f_op->iterate)
goto out_close;
buffer.name = name;
buffer.ino = child->d_inode->i_ino;
buffer.found = 0;
buffer.sequence = 0;
while (1) {
int old_seq = buffer.sequence;
error = vfs_readdir(file, filldir_one, &buffer);
error = iterate_dir(file, &buffer.ctx);
if (buffer.found) {
error = 0;
break;
......
......@@ -287,17 +287,17 @@ static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
}
static int
ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
ext2_readdir(struct file *file, struct dir_context *ctx)
{
loff_t pos = filp->f_pos;
struct inode *inode = file_inode(filp);
loff_t pos = ctx->pos;
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
unsigned long npages = dir_pages(inode);
unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
unsigned char *types = NULL;
int need_revalidate = filp->f_version != inode->i_version;
int need_revalidate = file->f_version != inode->i_version;
if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
return 0;
......@@ -314,16 +314,16 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
ext2_error(sb, __func__,
"bad page in #%lu",
inode->i_ino);
filp->f_pos += PAGE_CACHE_SIZE - offset;
ctx->pos += PAGE_CACHE_SIZE - offset;
return PTR_ERR(page);
}
kaddr = page_address(page);
if (unlikely(need_revalidate)) {
if (offset) {
offset = ext2_validate_entry(kaddr, offset, chunk_mask);
filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
ctx->pos = (n<<PAGE_CACHE_SHIFT) + offset;
}
filp->f_version = inode->i_version;
file->f_version = inode->i_version;
need_revalidate = 0;
}
de = (ext2_dirent *)(kaddr+offset);
......@@ -336,22 +336,19 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
return -EIO;
}
if (de->inode) {
int over;
unsigned char d_type = DT_UNKNOWN;
if (types && de->file_type < EXT2_FT_MAX)
d_type = types[de->file_type];
offset = (char *)de - kaddr;
over = filldir(dirent, de->name, de->name_len,
(n<<PAGE_CACHE_SHIFT) | offset,
le32_to_cpu(de->inode), d_type);
if (over) {
if (!dir_emit(ctx, de->name, de->name_len,
le32_to_cpu(de->inode),
d_type)) {
ext2_put_page(page);
return 0;
}
}
filp->f_pos += ext2_rec_len_from_disk(de->rec_len);
ctx->pos += ext2_rec_len_from_disk(de->rec_len);
}
ext2_put_page(page);
}
......@@ -724,7 +721,7 @@ int ext2_empty_dir (struct inode * inode)
const struct file_operations ext2_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext2_readdir,
.iterate = ext2_readdir,
.unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext2_compat_ioctl,
......
......@@ -28,8 +28,7 @@ static unsigned char ext3_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
static int ext3_dx_readdir(struct file * filp,
void * dirent, filldir_t filldir);
static int ext3_dx_readdir(struct file *, struct dir_context *);
static unsigned char get_dtype(struct super_block *sb, int filetype)
{
......@@ -91,36 +90,30 @@ int ext3_check_dir_entry (const char * function, struct inode * dir,
return error_msg == NULL ? 1 : 0;
}
static int ext3_readdir(struct file * filp,
void * dirent, filldir_t filldir)
static int ext3_readdir(struct file *file, struct dir_context *ctx)
{
int error = 0;
unsigned long offset;
int i, stored;
int i;
struct ext3_dir_entry_2 *de;
int err;
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
int ret = 0;
int dir_has_error = 0;
if (is_dx_dir(inode)) {
err = ext3_dx_readdir(filp, dirent, filldir);
if (err != ERR_BAD_DX_DIR) {
ret = err;
goto out;
}
err = ext3_dx_readdir(file, ctx);
if (err != ERR_BAD_DX_DIR)
return err;
/*
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
EXT3_I(file_inode(filp))->i_flags &= ~EXT3_INDEX_FL;
EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL;
}
stored = 0;
offset = filp->f_pos & (sb->s_blocksize - 1);
offset = ctx->pos & (sb->s_blocksize - 1);
while (!error && !stored && filp->f_pos < inode->i_size) {
unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb);
while (ctx->pos < inode->i_size) {
unsigned long blk = ctx->pos >> EXT3_BLOCK_SIZE_BITS(sb);
struct buffer_head map_bh;
struct buffer_head *bh = NULL;
......@@ -129,12 +122,12 @@ static int ext3_readdir(struct file * filp,
if (err > 0) {
pgoff_t index = map_bh.b_blocknr >>
(PAGE_CACHE_SHIFT - inode->i_blkbits);
if (!ra_has_index(&filp->f_ra, index))
if (!ra_has_index(&file->f_ra, index))
page_cache_sync_readahead(
sb->s_bdev->bd_inode->i_mapping,
&filp->f_ra, filp,
&file->f_ra, file,
index, 1);
filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
bh = ext3_bread(NULL, inode, blk, 0, &err);
}
......@@ -146,22 +139,21 @@ static int ext3_readdir(struct file * filp,
if (!dir_has_error) {
ext3_error(sb, __func__, "directory #%lu "
"contains a hole at offset %lld",
inode->i_ino, filp->f_pos);
inode->i_ino, ctx->pos);
dir_has_error = 1;
}
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
if (ctx->pos > inode->i_blocks << 9)
break;
filp->f_pos += sb->s_blocksize - offset;
ctx->pos += sb->s_blocksize - offset;
continue;
}
revalidate:
/* If the dir block has changed since the last call to
* readdir(2), then we might be pointing to an invalid
* dirent right now. Scan from the start of the block
* to make sure. */
if (filp->f_version != inode->i_version) {
if (offset && file->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
de = (struct ext3_dir_entry_2 *)
(bh->b_data + i);
......@@ -177,53 +169,40 @@ static int ext3_readdir(struct file * filp,
i += ext3_rec_len_from_disk(de->rec_len);
}
offset = i;
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
| offset;
filp->f_version = inode->i_version;
file->f_version = inode->i_version;
}
while (!error && filp->f_pos < inode->i_size
while (ctx->pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
bh, offset)) {
/* On error, skip the f_pos to the
/* On error, skip the to the
next block. */
filp->f_pos = (filp->f_pos |
ctx->pos = (ctx->pos |
(sb->s_blocksize - 1)) + 1;
brelse (bh);
ret = stored;
goto out;
break;
}
offset += ext3_rec_len_from_disk(de->rec_len);
if (le32_to_cpu(de->inode)) {
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
* version stamp to detect whether or
* not the directory has been modified
* during the copy operation.
*/
u64 version = filp->f_version;
error = filldir(dirent, de->name,
de->name_len,
filp->f_pos,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type));
if (error)
break;
if (version != filp->f_version)
goto revalidate;
stored ++;
if (!dir_emit(ctx, de->name, de->name_len,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type))) {
brelse(bh);
return 0;
}
}
filp->f_pos += ext3_rec_len_from_disk(de->rec_len);
ctx->pos += ext3_rec_len_from_disk(de->rec_len);
}
offset = 0;
brelse (bh);
if (ctx->pos < inode->i_size)
if (!dir_relax(inode))
return 0;
}
out:
return ret;
return 0;
}
static inline int is_32bit_api(void)
......@@ -452,62 +431,54 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
* for all entres on the fname linked list. (Normally there is only
* one entry on the linked list, unless there are 62 bit hash collisions.)
*/
static int call_filldir(struct file * filp, void * dirent,
filldir_t filldir, struct fname *fname)
static bool call_filldir(struct file *file, struct dir_context *ctx,
struct fname *fname)
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
struct inode *inode = file_inode(filp);
struct super_block * sb;
int error;
sb = inode->i_sb;
struct dir_private_info *info = file->private_data;
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
if (!fname) {
printk("call_filldir: called with null fname?!?\n");
return 0;
return true;
}
curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
while (fname) {
error = filldir(dirent, fname->name,
fname->name_len, curr_pos,
if (!dir_emit(ctx, fname->name, fname->name_len,
fname->inode,
get_dtype(sb, fname->file_type));
if (error) {
filp->f_pos = curr_pos;
get_dtype(sb, fname->file_type))) {
info->extra_fname = fname;
return error;
return false;
}
fname = fname->next;
}
return 0;
return true;
}
static int ext3_dx_readdir(struct file * filp,
void * dirent, filldir_t filldir)
static int ext3_dx_readdir(struct file *file, struct dir_context *ctx)
{
struct dir_private_info *info = filp->private_data;
struct inode *inode = file_inode(filp);
struct dir_private_info *info = file->private_data;
struct inode *inode = file_inode(file);
struct fname *fname;
int ret;
if (!info) {
info = ext3_htree_create_dir_info(filp, filp->f_pos);
info = ext3_htree_create_dir_info(file, ctx->pos);
if (!info)
return -ENOMEM;
filp->private_data = info;
file->private_data = info;
}
if (filp->f_pos == ext3_get_htree_eof(filp))
if (ctx->pos == ext3_get_htree_eof(file))
return 0; /* EOF */
/* Some one has messed with f_pos; reset the world */
if (info->last_pos != filp->f_pos) {
if (info->last_pos != ctx->pos) {
free_rb_tree_fname(&info->root);
info->curr_node = NULL;
info->extra_fname = NULL;
info->curr_hash = pos2maj_hash(filp, filp->f_pos);
info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
info->curr_hash = pos2maj_hash(file, ctx->pos);
info->curr_minor_hash = pos2min_hash(file, ctx->pos);
}
/*
......@@ -515,7 +486,7 @@ static int ext3_dx_readdir(struct file * filp,
* chain, return them first.
*/
if (info->extra_fname) {
if (call_filldir(filp, dirent, filldir, info->extra_fname))
if (!call_filldir(file, ctx, info->extra_fname))
goto finished;
info->extra_fname = NULL;
goto next_node;
......@@ -529,17 +500,17 @@ static int ext3_dx_readdir(struct file * filp,
* cached entries.
*/
if ((!info->curr_node) ||
(filp->f_version != inode->i_version)) {
(file->f_version != inode->i_version)) {
info->curr_node = NULL;
free_rb_tree_fname(&info->root);
filp->f_version = inode->i_version;
ret = ext3_htree_fill_tree(filp, info->curr_hash,
file->f_version = inode->i_version;
ret = ext3_htree_fill_tree(file, info->curr_hash,
info->curr_minor_hash,
&info->next_hash);
if (ret < 0)
return ret;
if (ret == 0) {
filp->f_pos = ext3_get_htree_eof(filp);
ctx->pos = ext3_get_htree_eof(file);
break;
}
info->curr_node = rb_first(&info->root);
......@@ -548,7 +519,7 @@ static int ext3_dx_readdir(struct file * filp,
fname = rb_entry(info->curr_node, struct fname, rb_hash);
info->curr_hash = fname->hash;
info->curr_minor_hash = fname->minor_hash;
if (call_filldir(filp, dirent, filldir, fname))
if (!call_filldir(file, ctx, fname))
break;
next_node:
info->curr_node = rb_next(info->curr_node);
......@@ -559,7 +530,7 @@ static int ext3_dx_readdir(struct file * filp,
info->curr_minor_hash = fname->minor_hash;
} else {
if (info->next_hash == ~0) {
filp->f_pos = ext3_get_htree_eof(filp);
ctx->pos = ext3_get_htree_eof(file);
break;
}
info->curr_hash = info->next_hash;
......@@ -567,7 +538,7 @@ static int ext3_dx_readdir(struct file * filp,
}
}
finished:
info->last_pos = filp->f_pos;
info->last_pos = ctx->pos;
return 0;
}
......@@ -582,7 +553,7 @@ static int ext3_release_dir (struct inode * inode, struct file * filp)
const struct file_operations ext3_dir_operations = {
.llseek = ext3_dir_llseek,
.read = generic_read_dir,
.readdir = ext3_readdir,
.iterate = ext3_readdir,
.unlocked_ioctl = ext3_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext3_compat_ioctl,
......
......@@ -29,8 +29,7 @@
#include "ext4.h"
#include "xattr.h"
static int ext4_dx_readdir(struct file *filp,
void *dirent, filldir_t filldir);
static int ext4_dx_readdir(struct file *, struct dir_context *);
/**
* Check if the given dir-inode refers to an htree-indexed directory
......@@ -103,60 +102,56 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
return 1;
}
static int ext4_readdir(struct file *filp,
void *dirent, filldir_t filldir)
static int ext4_readdir(struct file *file, struct dir_context *ctx)
{
int error = 0;
unsigned int offset;
int i, stored;
struct ext4_dir_entry_2 *de;
int err;
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
int ret = 0;
int dir_has_error = 0;
if (is_dx_dir(inode)) {
err = ext4_dx_readdir(filp, dirent, filldir);
err = ext4_dx_readdir(file, ctx);
if (err != ERR_BAD_DX_DIR) {
ret = err;
goto out;
return err;
}
/*
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
ext4_clear_inode_flag(file_inode(filp),
ext4_clear_inode_flag(file_inode(file),
EXT4_INODE_INDEX);
}
if (ext4_has_inline_data(inode)) {
int has_inline_data = 1;
ret = ext4_read_inline_dir(filp, dirent, filldir,
int ret = ext4_read_inline_dir(file, ctx,
&has_inline_data);
if (has_inline_data)
return ret;
}
stored = 0;
offset = filp->f_pos & (sb->s_blocksize - 1);
offset = ctx->pos & (sb->s_blocksize - 1);
while (!error && !stored && filp->f_pos < inode->i_size) {
while (ctx->pos < inode->i_size) {
struct ext4_map_blocks map;
struct buffer_head *bh = NULL;
map.m_lblk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb);
map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
map.m_len = 1;
err = ext4_map_blocks(NULL, inode, &map, 0);
if (err > 0) {
pgoff_t index = map.m_pblk >>
(PAGE_CACHE_SHIFT - inode->i_blkbits);
if (!ra_has_index(&filp->f_ra, index))
if (!ra_has_index(&file->f_ra, index))
page_cache_sync_readahead(
sb->s_bdev->bd_inode->i_mapping,
&filp->f_ra, filp,
&file->f_ra, file,
index, 1);
filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err);
}
......@@ -166,16 +161,16 @@ static int ext4_readdir(struct file *filp,
*/
if (!bh) {
if (!dir_has_error) {
EXT4_ERROR_FILE(filp, 0,
EXT4_ERROR_FILE(file, 0,
"directory contains a "
"hole at offset %llu",
(unsigned long long) filp->f_pos);
(unsigned long long) ctx->pos);
dir_has_error = 1;
}
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
if (ctx->pos > inode->i_blocks << 9)
break;
filp->f_pos += sb->s_blocksize - offset;
ctx->pos += sb->s_blocksize - offset;
continue;
}
......@@ -183,21 +178,20 @@ static int ext4_readdir(struct file *filp,
if (!buffer_verified(bh) &&
!ext4_dirent_csum_verify(inode,
(struct ext4_dir_entry *)bh->b_data)) {
EXT4_ERROR_FILE(filp, 0, "directory fails checksum "
EXT4_ERROR_FILE(file, 0, "directory fails checksum "
"at offset %llu",
(unsigned long long)filp->f_pos);
filp->f_pos += sb->s_blocksize - offset;
(unsigned long long)ctx->pos);
ctx->pos += sb->s_blocksize - offset;
brelse(bh);
continue;
}
set_buffer_verified(bh);
revalidate:
/* If the dir block has changed since the last call to
* readdir(2), then we might be pointing to an invalid
* dirent right now. Scan from the start of the block
* to make sure. */
if (filp->f_version != inode->i_version) {
if (file->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
de = (struct ext4_dir_entry_2 *)
(bh->b_data + i);
......@@ -214,57 +208,46 @@ static int ext4_readdir(struct file *filp,
sb->s_blocksize);
}
offset = i;
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
| offset;
filp->f_version = inode->i_version;
file->f_version = inode->i_version;
}
while (!error && filp->f_pos < inode->i_size
while (ctx->pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
if (ext4_check_dir_entry(inode, filp, de, bh,
if (ext4_check_dir_entry(inode, file, de, bh,
bh->b_data, bh->b_size,
offset)) {
/*
* On error, skip the f_pos to the next block
* On error, skip to the next block
*/
filp->f_pos = (filp->f_pos |
ctx->pos = (ctx->pos |
(sb->s_blocksize - 1)) + 1;
brelse(bh);
ret = stored;
goto out;
break;
}
offset += ext4_rec_len_from_disk(de->rec_len,
sb->s_blocksize);
if (le32_to_cpu(de->inode)) {
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
* version stamp to detect whether or
* not the directory has been modified
* during the copy operation.
*/
u64 version = filp->f_version;
error = filldir(dirent, de->name,
if (!dir_emit(ctx, de->name,
de->name_len,
filp->f_pos,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type));
if (error)
break;
if (version != filp->f_version)
goto revalidate;
stored++;
get_dtype(sb, de->file_type))) {
brelse(bh);
return 0;
}
}
filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
ctx->pos += ext4_rec_len_from_disk(de->rec_len,
sb->s_blocksize);
}
offset = 0;
brelse(bh);
if (ctx->pos < inode->i_size) {
if (!dir_relax(inode))
return 0;
}
}
out:
return ret;
return 0;
}
static inline int is_32bit_api(void)
......@@ -492,16 +475,12 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
* for all entres on the fname linked list. (Normally there is only
* one entry on the linked list, unless there are 62 bit hash collisions.)
*/
static int call_filldir(struct file *filp, void *dirent,
filldir_t filldir, struct fname *fname)
static int call_filldir(struct file *file, struct dir_context *ctx,
struct fname *fname)
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
struct inode *inode = file_inode(filp);
struct super_block *sb;
int error;
sb = inode->i_sb;
struct dir_private_info *info = file->private_data;
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
if (!fname) {
ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
......@@ -509,47 +488,44 @@ static int call_filldir(struct file *filp, void *dirent,
inode->i_ino, current->comm);
return 0;
}
curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
while (fname) {
error = filldir(dirent, fname->name,
fname->name_len, curr_pos,
if (!dir_emit(ctx, fname->name,
fname->name_len,
fname->inode,
get_dtype(sb, fname->file_type));
if (error) {
filp->f_pos = curr_pos;
get_dtype(sb, fname->file_type))) {
info->extra_fname = fname;
return error;
return 1;
}
fname = fname->next;
}
return 0;
}
static int ext4_dx_readdir(struct file *filp,
void *dirent, filldir_t filldir)
static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
{
struct dir_private_info *info = filp->private_data;
struct inode *inode = file_inode(filp);
struct dir_private_info *info = file->private_data;
struct inode *inode = file_inode(file);
struct fname *fname;
int ret;
if (!info) {
info = ext4_htree_create_dir_info(filp, filp->f_pos);
info = ext4_htree_create_dir_info(file, ctx->pos);
if (!info)
return -ENOMEM;
filp->private_data = info;
file->private_data = info;
}
if (filp->f_pos == ext4_get_htree_eof(filp))
if (ctx->pos == ext4_get_htree_eof(file))
return 0; /* EOF */
/* Some one has messed with f_pos; reset the world */
if (info->last_pos != filp->f_pos) {
if (info->last_pos != ctx->pos) {
free_rb_tree_fname(&info->root);
info->curr_node = NULL;
info->extra_fname = NULL;
info->curr_hash = pos2maj_hash(filp, filp->f_pos);
info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
info->curr_hash = pos2maj_hash(file, ctx->pos);
info->curr_minor_hash = pos2min_hash(file, ctx->pos);
}
/*
......@@ -557,7 +533,7 @@ static int ext4_dx_readdir(struct file *filp,
* chain, return them first.
*/
if (info->extra_fname) {
if (call_filldir(filp, dirent, filldir, info->extra_fname))
if (call_filldir(file, ctx, info->extra_fname))
goto finished;
info->extra_fname = NULL;
goto next_node;
......@@ -571,17 +547,17 @@ static int ext4_dx_readdir(struct file *filp,
* cached entries.
*/
if ((!info->curr_node) ||
(filp->f_version != inode->i_version)) {
(file->f_version != inode->i_version)) {
info->curr_node = NULL;
free_rb_tree_fname(&info->root);
filp->f_version = inode->i_version;
ret = ext4_htree_fill_tree(filp, info->curr_hash,
file->f_version = inode->i_version;
ret = ext4_htree_fill_tree(file, info->curr_hash,
info->curr_minor_hash,
&info->next_hash);
if (ret < 0)
return ret;
if (ret == 0) {
filp->f_pos = ext4_get_htree_eof(filp);
ctx->pos = ext4_get_htree_eof(file);
break;
}
info->curr_node = rb_first(&info->root);
......@@ -590,7 +566,7 @@ static int ext4_dx_readdir(struct file *filp,
fname = rb_entry(info->curr_node, struct fname, rb_hash);
info->curr_hash = fname->hash;
info->curr_minor_hash = fname->minor_hash;
if (call_filldir(filp, dirent, filldir, fname))
if (call_filldir(file, ctx, fname))
break;
next_node:
info->curr_node = rb_next(info->curr_node);
......@@ -601,7 +577,7 @@ static int ext4_dx_readdir(struct file *filp,
info->curr_minor_hash = fname->minor_hash;
} else {
if (info->next_hash == ~0) {
filp->f_pos = ext4_get_htree_eof(filp);
ctx->pos = ext4_get_htree_eof(file);
break;
}
info->curr_hash = info->next_hash;
......@@ -609,7 +585,7 @@ static int ext4_dx_readdir(struct file *filp,
}
}
finished:
info->last_pos = filp->f_pos;
info->last_pos = ctx->pos;
return 0;
}
......@@ -624,7 +600,7 @@ static int ext4_release_dir(struct inode *inode, struct file *filp)
const struct file_operations ext4_dir_operations = {
.llseek = ext4_dir_llseek,
.read = generic_read_dir,
.readdir = ext4_readdir,
.iterate = ext4_readdir,
.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
......
......@@ -2515,7 +2515,7 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
struct inode *parent,
struct inode *inode);
extern int ext4_read_inline_dir(struct file *filp,
void *dirent, filldir_t filldir,
struct dir_context *ctx,
int *has_inline_data);
extern int htree_inlinedir_to_tree(struct file *dir_file,
struct inode *dir, ext4_lblk_t block,
......
......@@ -1404,16 +1404,15 @@ int htree_inlinedir_to_tree(struct file *dir_file,
* offset as if '.' and '..' really take place.
*
*/
int ext4_read_inline_dir(struct file *filp,
void *dirent, filldir_t filldir,
int ext4_read_inline_dir(struct file *file,
struct dir_context *ctx,
int *has_inline_data)
{
int error = 0;
unsigned int offset, parent_ino;
int i, stored;
int i;
struct ext4_dir_entry_2 *de;
struct super_block *sb;
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
int ret, inline_size = 0;
struct ext4_iloc iloc;
void *dir_buf = NULL;
......@@ -1444,9 +1443,8 @@ int ext4_read_inline_dir(struct file *filp,
goto out;
sb = inode->i_sb;
stored = 0;
parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
offset = filp->f_pos;
offset = ctx->pos;
/*
* dotdot_offset and dotdot_size is the real offset and
......@@ -1460,104 +1458,74 @@ int ext4_read_inline_dir(struct file *filp,
extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
extra_size = extra_offset + inline_size;
while (!error && !stored && filp->f_pos < extra_size) {
revalidate:
/*
* If the version has changed since the last call to
* readdir(2), then we might be pointing to an invalid
* dirent right now. Scan from the start of the inline
* dir to make sure.
*/
if (filp->f_version != inode->i_version) {
for (i = 0; i < extra_size && i < offset;) {
/*
* "." is with offset 0 and
* ".." is dotdot_offset.
*/
if (!i) {
i = dotdot_offset;
continue;
} else if (i == dotdot_offset) {
i = dotdot_size;
continue;
}
/* for other entry, the real offset in
* the buf has to be tuned accordingly.
*/
de = (struct ext4_dir_entry_2 *)
(dir_buf + i - extra_offset);
/* It's too expensive to do a full
* dirent test each time round this
* loop, but we do have to test at
* least that it is non-zero. A
* failure will be detected in the
* dirent test below. */
if (ext4_rec_len_from_disk(de->rec_len,
extra_size) < EXT4_DIR_REC_LEN(1))
break;
i += ext4_rec_len_from_disk(de->rec_len,
extra_size);
}
offset = i;
filp->f_pos = offset;
filp->f_version = inode->i_version;
}
while (!error && filp->f_pos < extra_size) {
if (filp->f_pos == 0) {
error = filldir(dirent, ".", 1, 0, inode->i_ino,
DT_DIR);
if (error)
break;
stored++;
filp->f_pos = dotdot_offset;
/*
* If the version has changed since the last call to
* readdir(2), then we might be pointing to an invalid
* dirent right now. Scan from the start of the inline
* dir to make sure.
*/
if (file->f_version != inode->i_version) {
for (i = 0; i < extra_size && i < offset;) {
/*
* "." is with offset 0 and
* ".." is dotdot_offset.
*/
if (!i) {
i = dotdot_offset;
continue;
} else if (i == dotdot_offset) {
i = dotdot_size;
continue;
}
/* for other entry, the real offset in
* the buf has to be tuned accordingly.
*/
de = (struct ext4_dir_entry_2 *)
(dir_buf + i - extra_offset);
/* It's too expensive to do a full
* dirent test each time round this
* loop, but we do have to test at
* least that it is non-zero. A
* failure will be detected in the
* dirent test below. */
if (ext4_rec_len_from_disk(de->rec_len, extra_size)
< EXT4_DIR_REC_LEN(1))
break;
i += ext4_rec_len_from_disk(de->rec_len,
extra_size);
}
offset = i;
ctx->pos = offset;
file->f_version = inode->i_version;
}
if (filp->f_pos == dotdot_offset) {
error = filldir(dirent, "..", 2,
dotdot_offset,
parent_ino, DT_DIR);
if (error)
break;
stored++;
while (ctx->pos < extra_size) {
if (ctx->pos == 0) {
if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
goto out;
ctx->pos = dotdot_offset;
continue;
}
filp->f_pos = dotdot_size;
continue;
}
if (ctx->pos == dotdot_offset) {
if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR))
goto out;
ctx->pos = dotdot_size;
continue;
}
de = (struct ext4_dir_entry_2 *)
(dir_buf + filp->f_pos - extra_offset);
if (ext4_check_dir_entry(inode, filp, de,
iloc.bh, dir_buf,
extra_size, filp->f_pos)) {
ret = stored;
de = (struct ext4_dir_entry_2 *)
(dir_buf + ctx->pos - extra_offset);
if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf,
extra_size, ctx->pos))
goto out;
if (le32_to_cpu(de->inode)) {
if (!dir_emit(ctx, de->name, de->name_len,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type)))
goto out;
}
if (le32_to_cpu(de->inode)) {
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
* version stamp to detect whether or
* not the directory has been modified
* during the copy operation.
*/
u64 version = filp->f_version;
error = filldir(dirent, de->name,
de->name_len,
filp->f_pos,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type));
if (error)
break;
if (version != filp->f_version)
goto revalidate;
stored++;
}
filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
extra_size);
}
ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
}
out:
kfree(dir_buf);
......
......@@ -591,24 +591,19 @@ bool f2fs_empty_dir(struct inode *dir)
return true;
}
static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir)
static int f2fs_readdir(struct file *file, struct dir_context *ctx)
{
unsigned long pos = file->f_pos;
struct inode *inode = file_inode(file);
unsigned long npages = dir_blocks(inode);
unsigned char *types = NULL;
unsigned int bit_pos = 0, start_bit_pos = 0;
int over = 0;
struct f2fs_dentry_block *dentry_blk = NULL;
struct f2fs_dir_entry *de = NULL;
struct page *dentry_page = NULL;
unsigned int n = 0;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
unsigned char d_type = DT_UNKNOWN;
int slots;
types = f2fs_filetype_table;
bit_pos = (pos % NR_DENTRY_IN_BLOCK);
n = (pos / NR_DENTRY_IN_BLOCK);
bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
for ( ; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n);
......@@ -618,31 +613,28 @@ static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir)
start_bit_pos = bit_pos;
dentry_blk = kmap(dentry_page);
while (bit_pos < NR_DENTRY_IN_BLOCK) {
d_type = DT_UNKNOWN;
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
NR_DENTRY_IN_BLOCK,
bit_pos);
if (bit_pos >= NR_DENTRY_IN_BLOCK)
break;
ctx->pos += bit_pos - start_bit_pos;
de = &dentry_blk->dentry[bit_pos];
if (types && de->file_type < F2FS_FT_MAX)
d_type = types[de->file_type];
over = filldir(dirent,
dentry_blk->filename[bit_pos],
le16_to_cpu(de->name_len),
(n * NR_DENTRY_IN_BLOCK) + bit_pos,
le32_to_cpu(de->ino), d_type);
if (over) {
file->f_pos += bit_pos - start_bit_pos;
if (de->file_type < F2FS_FT_MAX)
d_type = f2fs_filetype_table[de->file_type];
else
d_type = DT_UNKNOWN;
if (!dir_emit(ctx,
dentry_blk->filename[bit_pos],
le16_to_cpu(de->name_len),
le32_to_cpu(de->ino), d_type))
goto success;
}
slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
bit_pos += slots;
}
bit_pos = 0;
file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK;
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
dentry_page = NULL;
......@@ -659,7 +651,7 @@ static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir)
const struct file_operations f2fs_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = f2fs_readdir,
.iterate = f2fs_readdir,
.fsync = f2fs_sync_file,
.unlocked_ioctl = f2fs_ioctl,
};
......@@ -543,6 +543,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
EXPORT_SYMBOL_GPL(fat_search_long);
struct fat_ioctl_filldir_callback {
struct dir_context ctx;
void __user *dirent;
int result;
/* for dir ioctl */
......@@ -552,8 +553,9 @@ struct fat_ioctl_filldir_callback {
int short_len;
};
static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
filldir_t filldir, int short_only, int both)
static int __fat_readdir(struct inode *inode, struct file *file,
struct dir_context *ctx, int short_only,
struct fat_ioctl_filldir_callback *both)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
......@@ -564,27 +566,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
unsigned char bufname[FAT_MAX_SHORT_SIZE];
int isvfat = sbi->options.isvfat;
const char *fill_name = NULL;
unsigned long inum;
unsigned long lpos, dummy, *furrfu = &lpos;
int fake_offset = 0;
loff_t cpos;
int short_len = 0, fill_len = 0;
int ret = 0;
mutex_lock(&sbi->s_lock);
cpos = filp->f_pos;
cpos = ctx->pos;
/* Fake . and .. for the root directory. */
if (inode->i_ino == MSDOS_ROOT_INO) {
while (cpos < 2) {
if (filldir(dirent, "..", cpos+1, cpos,
MSDOS_ROOT_INO, DT_DIR) < 0)
goto out;
cpos++;
filp->f_pos++;
}
if (cpos == 2) {
dummy = 2;
furrfu = &dummy;
if (!dir_emit_dots(file, ctx))
goto out;
if (ctx->pos == 2) {
fake_offset = 1;
cpos = 0;
}
}
......@@ -619,7 +614,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
int status = fat_parse_long(inode, &cpos, &bh, &de,
&unicode, &nr_slots);
if (status < 0) {
filp->f_pos = cpos;
ctx->pos = cpos;
ret = status;
goto out;
} else if (status == PARSE_INVALID)
......@@ -639,6 +634,19 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
/* !both && !short_only, so we don't need shortname. */
if (!both)
goto start_filldir;
short_len = fat_parse_short(sb, de, bufname,
sbi->options.dotsOK);
if (short_len == 0)
goto record_end;
/* hack for fat_ioctl_filldir() */
both->longname = fill_name;
both->long_len = fill_len;
both->shortname = bufname;
both->short_len = short_len;
fill_name = NULL;
fill_len = 0;
goto start_filldir;
}
}
......@@ -646,28 +654,21 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
if (short_len == 0)
goto record_end;
if (nr_slots) {
/* hack for fat_ioctl_filldir() */
struct fat_ioctl_filldir_callback *p = dirent;
p->longname = fill_name;
p->long_len = fill_len;
p->shortname = bufname;
p->short_len = short_len;
fill_name = NULL;
fill_len = 0;
} else {
fill_name = bufname;
fill_len = short_len;
}
fill_name = bufname;
fill_len = short_len;
start_filldir:
lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
inum = inode->i_ino;
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
inum = parent_ino(filp->f_path.dentry);
if (!fake_offset)
ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
if (!dir_emit_dot(file, ctx))
goto fill_failed;
} else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
if (!dir_emit_dotdot(file, ctx))
goto fill_failed;
} else {
unsigned long inum;
loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos);
if (tmp) {
......@@ -675,18 +676,17 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
iput(tmp);
} else
inum = iunique(sb, MSDOS_ROOT_INO);
if (!dir_emit(ctx, fill_name, fill_len, inum,
(de->attr & ATTR_DIR) ? DT_DIR : DT_REG))
goto fill_failed;
}
if (filldir(dirent, fill_name, fill_len, *furrfu, inum,
(de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
goto fill_failed;
record_end:
furrfu = &lpos;
filp->f_pos = cpos;
fake_offset = 0;
ctx->pos = cpos;
goto get_new;
end_of_dir:
filp->f_pos = cpos;
ctx->pos = cpos;
fill_failed:
brelse(bh);
if (unicode)
......@@ -696,10 +696,9 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
return ret;
}
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int fat_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
return __fat_readdir(file_inode(file), file, ctx, 0, NULL);
}
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
......@@ -755,20 +754,25 @@ efault: \
FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)
static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
static int fat_ioctl_readdir(struct inode *inode, struct file *file,
void __user *dirent, filldir_t filldir,
int short_only, int both)
{
struct fat_ioctl_filldir_callback buf;
struct fat_ioctl_filldir_callback buf = {
.ctx.actor = filldir,
.dirent = dirent
};
int ret;
buf.dirent = dirent;
buf.result = 0;
mutex_lock(&inode->i_mutex);
buf.ctx.pos = file->f_pos;
ret = -ENOENT;
if (!IS_DEADDIR(inode)) {
ret = __fat_readdir(inode, filp, &buf, filldir,
short_only, both);
ret = __fat_readdir(inode, file, &buf.ctx,
short_only, both ? &buf : NULL);
file->f_pos = buf.ctx.pos;
}
mutex_unlock(&inode->i_mutex);
if (ret >= 0)
......@@ -854,7 +858,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
const struct file_operations fat_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = fat_readdir,
.iterate = fat_readdir,
.unlocked_ioctl = fat_dir_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fat_compat_dir_ioctl,
......
......@@ -49,7 +49,7 @@
static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int);
static int vxfs_readdir(struct file *, void *, filldir_t);
static int vxfs_readdir(struct file *, struct dir_context *);
const struct inode_operations vxfs_dir_inode_ops = {
.lookup = vxfs_lookup,
......@@ -58,7 +58,7 @@ const struct inode_operations vxfs_dir_inode_ops = {
const struct file_operations vxfs_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = vxfs_readdir,
.iterate = vxfs_readdir,
};
......@@ -235,7 +235,7 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
* Zero.
*/
static int
vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
vxfs_readdir(struct file *fp, struct dir_context *ctx)
{
struct inode *ip = file_inode(fp);
struct super_block *sbp = ip->i_sb;
......@@ -243,20 +243,17 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
u_long page, npages, block, pblocks, nblocks, offset;
loff_t pos;
switch ((long)fp->f_pos) {
case 0:
if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
goto out;
fp->f_pos++;
/* fallthrough */
case 1:
if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
goto out;
fp->f_pos++;
/* fallthrough */
if (ctx->pos == 0) {
if (!dir_emit_dot(fp, ctx))
return 0;
ctx->pos = 1;
}
pos = fp->f_pos - 2;
if (ctx->pos == 1) {
if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
return 0;
ctx->pos = 2;
}
pos = ctx->pos - 2;
if (pos > VXFS_DIRROUND(ip->i_size))
return 0;
......@@ -270,16 +267,16 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
for (; page < npages; page++, block = 0) {
caddr_t kaddr;
char *kaddr;
struct page *pp;
pp = vxfs_get_page(ip->i_mapping, page);
if (IS_ERR(pp))
continue;
kaddr = (caddr_t)page_address(pp);
kaddr = (char *)page_address(pp);
for (; block <= nblocks && block <= pblocks; block++) {
caddr_t baddr, limit;
char *baddr, *limit;
struct vxfs_dirblk *dbp;
struct vxfs_direct *de;
......@@ -292,21 +289,18 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
(kaddr + offset) :
(baddr + VXFS_DIRBLKOV(dbp)));
for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
int over;
for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
if (!de->d_reclen)
break;
if (!de->d_ino)
continue;
offset = (caddr_t)de - kaddr;
over = filler(retp, de->d_name, de->d_namelen,
((page << PAGE_CACHE_SHIFT) | offset) + 2,
de->d_ino, DT_UNKNOWN);
if (over) {
offset = (char *)de - kaddr;
ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
if (!dir_emit(ctx, de->d_name, de->d_namelen,
de->d_ino, DT_UNKNOWN)) {
vxfs_put_page(pp);
goto done;
return 0;
}
}
offset = 0;
......@@ -314,9 +308,6 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
vxfs_put_page(pp);
offset = 0;
}
done:
fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
out:
ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
return 0;
}
......@@ -14,7 +14,7 @@
#include <linux/namei.h>
#include <linux/slab.h>
static bool fuse_use_readdirplus(struct inode *dir, struct file *filp)
static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
{
struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_inode *fi = get_fuse_inode(dir);
......@@ -25,7 +25,7 @@ static bool fuse_use_readdirplus(struct inode *dir, struct file *filp)
return true;
if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
return true;
if (filp->f_pos == 0)
if (ctx->pos == 0)
return true;
return false;
}
......@@ -1165,25 +1165,23 @@ static int fuse_permission(struct inode *inode, int mask)
}
static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
void *dstbuf, filldir_t filldir)
struct dir_context *ctx)
{
while (nbytes >= FUSE_NAME_OFFSET) {
struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
size_t reclen = FUSE_DIRENT_SIZE(dirent);
int over;
if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
return -EIO;
if (reclen > nbytes)
break;
over = filldir(dstbuf, dirent->name, dirent->namelen,
file->f_pos, dirent->ino, dirent->type);
if (over)
if (!dir_emit(ctx, dirent->name, dirent->namelen,
dirent->ino, dirent->type))
break;
buf += reclen;
nbytes -= reclen;
file->f_pos = dirent->off;
ctx->pos = dirent->off;
}
return 0;
......@@ -1284,7 +1282,7 @@ static int fuse_direntplus_link(struct file *file,
}
static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
void *dstbuf, filldir_t filldir, u64 attr_version)
struct dir_context *ctx, u64 attr_version)
{
struct fuse_direntplus *direntplus;
struct fuse_dirent *dirent;
......@@ -1309,10 +1307,9 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
we need to send a FORGET for each of those
which we did not link.
*/
over = filldir(dstbuf, dirent->name, dirent->namelen,
file->f_pos, dirent->ino,
dirent->type);
file->f_pos = dirent->off;
over = !dir_emit(ctx, dirent->name, dirent->namelen,
dirent->ino, dirent->type);
ctx->pos = dirent->off;
}
buf += reclen;
......@@ -1326,7 +1323,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
return 0;
}
static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
static int fuse_readdir(struct file *file, struct dir_context *ctx)
{
int plus, err;
size_t nbytes;
......@@ -1349,17 +1346,17 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
return -ENOMEM;
}
plus = fuse_use_readdirplus(inode, file);
plus = fuse_use_readdirplus(inode, ctx);
req->out.argpages = 1;
req->num_pages = 1;
req->pages[0] = page;
req->page_descs[0].length = PAGE_SIZE;
if (plus) {
attr_version = fuse_get_attr_version(fc);
fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
fuse_read_fill(req, file, ctx->pos, PAGE_SIZE,
FUSE_READDIRPLUS);
} else {
fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
fuse_read_fill(req, file, ctx->pos, PAGE_SIZE,
FUSE_READDIR);
}
fuse_request_send(fc, req);
......@@ -1369,11 +1366,11 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
if (!err) {
if (plus) {
err = parse_dirplusfile(page_address(page), nbytes,
file, dstbuf, filldir,
file, ctx,
attr_version);
} else {
err = parse_dirfile(page_address(page), nbytes, file,
dstbuf, filldir);
ctx);
}
}
......@@ -1886,7 +1883,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
static const struct file_operations fuse_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = fuse_readdir,
.iterate = fuse_readdir,
.open = fuse_dir_open,
.release = fuse_dir_release,
.fsync = fuse_dir_fsync,
......
......@@ -1212,9 +1212,7 @@ static int compare_dents(const void *a, const void *b)
/**
* do_filldir_main - read out directory entries
* @dip: The GFS2 inode
* @offset: The offset in the file to read from
* @opaque: opaque data to pass to filldir
* @filldir: The function to pass entries to
* @ctx: what to feed the entries to
* @darr: an array of struct gfs2_dirent pointers to read
* @entries: the number of entries in darr
* @copied: pointer to int that's non-zero if a entry has been copied out
......@@ -1224,11 +1222,10 @@ static int compare_dents(const void *a, const void *b)
* the possibility that they will fall into different readdir buffers or
* that someone will want to seek to that location.
*
* Returns: errno, >0 on exception from filldir
* Returns: errno, >0 if the actor tells you to stop
*/
static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
void *opaque, filldir_t filldir,
static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx,
const struct gfs2_dirent **darr, u32 entries,
int *copied)
{
......@@ -1236,7 +1233,6 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
u64 off, off_next;
unsigned int x, y;
int run = 0;
int error = 0;
sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);
......@@ -1253,9 +1249,9 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
off_next = be32_to_cpu(dent_next->de_hash);
off_next = gfs2_disk_hash2offset(off_next);
if (off < *offset)
if (off < ctx->pos)
continue;
*offset = off;
ctx->pos = off;
if (off_next == off) {
if (*copied && !run)
......@@ -1264,26 +1260,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
} else
run = 0;
} else {
if (off < *offset)
if (off < ctx->pos)
continue;
*offset = off;
ctx->pos = off;
}
error = filldir(opaque, (const char *)(dent + 1),
if (!dir_emit(ctx, (const char *)(dent + 1),
be16_to_cpu(dent->de_name_len),
off, be64_to_cpu(dent->de_inum.no_addr),
be16_to_cpu(dent->de_type));
if (error)
be64_to_cpu(dent->de_inum.no_addr),
be16_to_cpu(dent->de_type)))
return 1;
*copied = 1;
}
/* Increment the *offset by one, so the next time we come into the
/* Increment the ctx->pos by one, so the next time we come into the
do_filldir fxn, we get the next entry instead of the last one in the
current leaf */
(*offset)++;
ctx->pos++;
return 0;
}
......@@ -1307,8 +1302,8 @@ static void gfs2_free_sort_buffer(void *ptr)
kfree(ptr);
}
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir, int *copied, unsigned *depth,
static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
int *copied, unsigned *depth,
u64 leaf_no)
{
struct gfs2_inode *ip = GFS2_I(inode);
......@@ -1386,8 +1381,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
} while(lfn);
BUG_ON(entries2 != entries);
error = do_filldir_main(ip, offset, opaque, filldir, darr,
entries, copied);
error = do_filldir_main(ip, ctx, darr, entries, copied);
out_free:
for(i = 0; i < leaf; i++)
brelse(larr[i]);
......@@ -1446,15 +1440,13 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
/**
* dir_e_read - Reads the entries from a directory into a filldir buffer
* @dip: dinode pointer
* @offset: the hash of the last entry read shifted to the right once
* @opaque: buffer for the filldir function to fill
* @filldir: points to the filldir function to use
* @ctx: actor to feed the entries to
*
* Returns: errno
*/
static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir, struct file_ra_state *f_ra)
static int dir_e_read(struct inode *inode, struct dir_context *ctx,
struct file_ra_state *f_ra)
{
struct gfs2_inode *dip = GFS2_I(inode);
u32 hsize, len = 0;
......@@ -1465,7 +1457,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
unsigned depth = 0;
hsize = 1 << dip->i_depth;
hash = gfs2_dir_offset2hash(*offset);
hash = gfs2_dir_offset2hash(ctx->pos);
index = hash >> (32 - dip->i_depth);
if (dip->i_hash_cache == NULL)
......@@ -1477,7 +1469,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
gfs2_dir_readahead(inode, hsize, index, f_ra);
while (index < hsize) {
error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
error = gfs2_dir_read_leaf(inode, ctx,
&copied, &depth,
be64_to_cpu(lp[index]));
if (error)
......@@ -1492,8 +1484,8 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
return error;
}
int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir, struct file_ra_state *f_ra)
int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
struct file_ra_state *f_ra)
{
struct gfs2_inode *dip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
......@@ -1507,7 +1499,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
return 0;
if (dip->i_diskflags & GFS2_DIF_EXHASH)
return dir_e_read(inode, offset, opaque, filldir, f_ra);
return dir_e_read(inode, ctx, f_ra);
if (!gfs2_is_stuffed(dip)) {
gfs2_consist_inode(dip);
......@@ -1539,7 +1531,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
error = -EIO;
goto out;
}
error = do_filldir_main(dip, offset, opaque, filldir, darr,
error = do_filldir_main(dip, ctx, darr,
dip->i_entries, &copied);
out:
kfree(darr);
......
......@@ -24,8 +24,8 @@ extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
const struct gfs2_inode *ip);
extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry);
extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir, struct file_ra_state *f_ra);
extern int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
struct file_ra_state *f_ra);
extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
const struct gfs2_inode *nip, unsigned int new_type);
......
......@@ -64,6 +64,7 @@ static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len,
}
struct get_name_filldir {
struct dir_context ctx;
struct gfs2_inum_host inum;
char *name;
};
......@@ -88,9 +89,11 @@ static int gfs2_get_name(struct dentry *parent, char *name,
struct inode *dir = parent->d_inode;
struct inode *inode = child->d_inode;
struct gfs2_inode *dip, *ip;
struct get_name_filldir gnfd;
struct get_name_filldir gnfd = {
.ctx.actor = get_name_filldir,
.name = name
};
struct gfs2_holder gh;
u64 offset = 0;
int error;
struct file_ra_state f_ra = { .start = 0 };
......@@ -106,13 +109,12 @@ static int gfs2_get_name(struct dentry *parent, char *name,
*name = 0;
gnfd.inum.no_addr = ip->i_no_addr;
gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
gnfd.name = name;
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
if (error)
return error;
error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, &f_ra);
error = gfs2_dir_read(dir, &gnfd.ctx, &f_ra);
gfs2_glock_dq_uninit(&gh);
......
......@@ -82,35 +82,28 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int whence)
}
/**
* gfs2_readdir - Read directory entries from a directory
* gfs2_readdir - Iterator for a directory
* @file: The directory to read from
* @dirent: Buffer for dirents
* @filldir: Function used to do the copying
* @ctx: What to feed directory entries to
*
* Returns: errno
*/
static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
static int gfs2_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *dir = file->f_mapping->host;
struct gfs2_inode *dip = GFS2_I(dir);
struct gfs2_holder d_gh;
u64 offset = file->f_pos;
int error;
gfs2_holder_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
error = gfs2_glock_nq(&d_gh);
if (error) {
gfs2_holder_uninit(&d_gh);
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
if (error)
return error;
}
error = gfs2_dir_read(dir, &offset, dirent, filldir, &file->f_ra);
error = gfs2_dir_read(dir, ctx, &file->f_ra);
gfs2_glock_dq_uninit(&d_gh);
file->f_pos = offset;
return error;
}
......@@ -1048,7 +1041,7 @@ const struct file_operations gfs2_file_fops = {
};
const struct file_operations gfs2_dir_fops = {
.readdir = gfs2_readdir,
.iterate = gfs2_readdir,
.unlocked_ioctl = gfs2_ioctl,
.open = gfs2_open,
.release = gfs2_release,
......@@ -1078,7 +1071,7 @@ const struct file_operations gfs2_file_fops_nolock = {
};
const struct file_operations gfs2_dir_fops_nolock = {
.readdir = gfs2_readdir,
.iterate = gfs2_readdir,
.unlocked_ioctl = gfs2_ioctl,
.open = gfs2_open,
.release = gfs2_release,
......
......@@ -51,9 +51,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
/*
* hfs_readdir
*/
static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int hfs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFS_MAX_NAMELEN];
......@@ -62,7 +62,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct hfs_readdir_data *rd;
u16 type;
if (filp->f_pos >= inode->i_size)
if (ctx->pos >= inode->i_size)
return 0;
err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
......@@ -73,14 +73,13 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (err)
goto out;
switch ((u32)filp->f_pos) {
case 0:
if (ctx->pos == 0) {
/* This is completely artificial... */
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
if (!dir_emit_dot(file, ctx))
goto out;
filp->f_pos++;
/* fall through */
case 1:
ctx->pos = 1;
}
if (ctx->pos == 1) {
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
err = -EIO;
goto out;
......@@ -97,18 +96,16 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
// err = -EIO;
// goto out;
//}
if (filldir(dirent, "..", 2, 1,
if (!dir_emit(ctx, "..", 2,
be32_to_cpu(entry.thread.ParID), DT_DIR))
goto out;
filp->f_pos++;
/* fall through */
default:
if (filp->f_pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, filp->f_pos - 1);
if (err)
goto out;
ctx->pos = 2;
}
if (ctx->pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, ctx->pos - 1);
if (err)
goto out;
for (;;) {
if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
......@@ -131,7 +128,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO;
goto out;
}
if (filldir(dirent, strbuf, len, filp->f_pos,
if (!dir_emit(ctx, strbuf, len,
be32_to_cpu(entry.dir.DirID), DT_DIR))
break;
} else if (type == HFS_CDR_FIL) {
......@@ -140,7 +137,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO;
goto out;
}
if (filldir(dirent, strbuf, len, filp->f_pos,
if (!dir_emit(ctx, strbuf, len,
be32_to_cpu(entry.file.FlNum), DT_REG))
break;
} else {
......@@ -148,22 +145,22 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO;
goto out;
}
filp->f_pos++;
if (filp->f_pos >= inode->i_size)
ctx->pos++;
if (ctx->pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, 1);
if (err)
goto out;
}
rd = filp->private_data;
rd = file->private_data;
if (!rd) {
rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
if (!rd) {
err = -ENOMEM;
goto out;
}
filp->private_data = rd;
rd->file = filp;
file->private_data = rd;
rd->file = file;
list_add(&rd->list, &HFS_I(inode)->open_dir_list);
}
memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
......@@ -306,7 +303,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
const struct file_operations hfs_dir_operations = {
.read = generic_read_dir,
.readdir = hfs_readdir,
.iterate = hfs_readdir,
.llseek = generic_file_llseek,
.release = hfs_dir_release,
};
......
......@@ -121,9 +121,9 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(err);
}
static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int hfsplus_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFSPLUS_MAX_STRLEN + 1];
......@@ -132,7 +132,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct hfsplus_readdir_data *rd;
u16 type;
if (filp->f_pos >= inode->i_size)
if (file->f_pos >= inode->i_size)
return 0;
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
......@@ -143,14 +143,13 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (err)
goto out;
switch ((u32)filp->f_pos) {
case 0:
if (ctx->pos == 0) {
/* This is completely artificial... */
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
if (!dir_emit_dot(file, ctx))
goto out;
filp->f_pos++;
/* fall through */
case 1:
ctx->pos = 1;
}
if (ctx->pos == 1) {
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
err = -EIO;
goto out;
......@@ -168,19 +167,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO;
goto out;
}
if (filldir(dirent, "..", 2, 1,
if (!dir_emit(ctx, "..", 2,
be32_to_cpu(entry.thread.parentID), DT_DIR))
goto out;
filp->f_pos++;
/* fall through */
default:
if (filp->f_pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, filp->f_pos - 1);
if (err)
goto out;
ctx->pos = 2;
}
if (ctx->pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, ctx->pos - 1);
if (err)
goto out;
for (;;) {
if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) {
pr_err("walked past end of dir\n");
......@@ -211,7 +207,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
HFSPLUS_SB(sb)->hidden_dir->i_ino ==
be32_to_cpu(entry.folder.id))
goto next;
if (filldir(dirent, strbuf, len, filp->f_pos,
if (!dir_emit(ctx, strbuf, len,
be32_to_cpu(entry.folder.id), DT_DIR))
break;
} else if (type == HFSPLUS_FILE) {
......@@ -220,7 +216,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO;
goto out;
}
if (filldir(dirent, strbuf, len, filp->f_pos,
if (!dir_emit(ctx, strbuf, len,
be32_to_cpu(entry.file.id), DT_REG))
break;
} else {
......@@ -229,22 +225,22 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto out;
}
next:
filp->f_pos++;
if (filp->f_pos >= inode->i_size)
ctx->pos++;
if (ctx->pos >= inode->i_size)
goto out;
err = hfs_brec_goto(&fd, 1);
if (err)
goto out;
}
rd = filp->private_data;
rd = file->private_data;
if (!rd) {
rd = kmalloc(sizeof(struct hfsplus_readdir_data), GFP_KERNEL);
if (!rd) {
err = -ENOMEM;
goto out;
}
filp->private_data = rd;
rd->file = filp;
file->private_data = rd;
rd->file = file;
list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
}
memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
......@@ -538,7 +534,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
const struct file_operations hfsplus_dir_operations = {
.fsync = hfsplus_file_fsync,
.read = generic_read_dir,
.readdir = hfsplus_readdir,
.iterate = hfsplus_readdir,
.unlocked_ioctl = hfsplus_ioctl,
.llseek = generic_file_llseek,
.release = hfsplus_dir_release,
......
......@@ -277,7 +277,7 @@ static const struct super_operations hostfs_sbops = {
.show_options = hostfs_show_options,
};
int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
int hostfs_readdir(struct file *file, struct dir_context *ctx)
{
void *dir;
char *name;
......@@ -292,12 +292,11 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
__putname(name);
if (dir == NULL)
return -error;
next = file->f_pos;
next = ctx->pos;
while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
error = (*filldir)(ent, name, len, file->f_pos,
ino, type);
if (error) break;
file->f_pos = next;
if (!dir_emit(ctx, name, len, ino, type))
break;
ctx->pos = next;
}
close_dir(dir);
return 0;
......@@ -393,7 +392,7 @@ static const struct file_operations hostfs_file_fops = {
static const struct file_operations hostfs_dir_fops = {
.llseek = generic_file_llseek,
.readdir = hostfs_readdir,
.iterate = hostfs_readdir,
.read = generic_read_dir,
};
......
......@@ -57,14 +57,14 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
return -ESPIPE;
}
static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int hpfs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
struct quad_buffer_head qbh;
struct hpfs_dirent *de;
int lc;
long old_pos;
loff_t next_pos;
unsigned char *tempname;
int c1, c2 = 0;
int ret = 0;
......@@ -105,11 +105,11 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
}
lc = hpfs_sb(inode->i_sb)->sb_lowercase;
if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */
filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */
if (ctx->pos == 12) { /* diff -r requires this (note, that diff -r */
ctx->pos = 13; /* also fails on msdos filesystem in 2.0) */
goto out;
}
if (filp->f_pos == 13) {
if (ctx->pos == 13) {
ret = -ENOENT;
goto out;
}
......@@ -120,33 +120,34 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
accepted by filldir, but what can I do?
maybe killall -9 ls helps */
if (hpfs_sb(inode->i_sb)->sb_chk)
if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
if (hpfs_stop_cycles(inode->i_sb, ctx->pos, &c1, &c2, "hpfs_readdir")) {
ret = -EFSERROR;
goto out;
}
if (filp->f_pos == 12)
if (ctx->pos == 12)
goto out;
if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
if (ctx->pos == 3 || ctx->pos == 4 || ctx->pos == 5) {
printk("HPFS: warning: pos==%d\n",(int)ctx->pos);
goto out;
}
if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
if (ctx->pos == 0) {
if (!dir_emit_dot(file, ctx))
goto out;
filp->f_pos = 11;
ctx->pos = 11;
}
if (filp->f_pos == 11) {
if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0)
if (ctx->pos == 11) {
if (!dir_emit(ctx, "..", 2, hpfs_inode->i_parent_dir, DT_DIR))
goto out;
filp->f_pos = 1;
ctx->pos = 1;
}
if (filp->f_pos == 1) {
filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
hpfs_add_pos(inode, &filp->f_pos);
filp->f_version = inode->i_version;
if (ctx->pos == 1) {
ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
hpfs_add_pos(inode, &file->f_pos);
file->f_version = inode->i_version;
}
old_pos = filp->f_pos;
if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
next_pos = ctx->pos;
if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) {
ctx->pos = next_pos;
ret = -EIOERROR;
goto out;
}
......@@ -154,20 +155,21 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (hpfs_sb(inode->i_sb)->sb_chk) {
if (de->first && !de->last && (de->namelen != 2
|| de ->name[0] != 1 || de->name[1] != 1))
hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08lx", old_pos);
hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08lx", (unsigned long)ctx->pos);
if (de->last && (de->namelen != 1 || de ->name[0] != 255))
hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08lx", old_pos);
hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08lx", (unsigned long)ctx->pos);
}
hpfs_brelse4(&qbh);
ctx->pos = next_pos;
goto again;
}
tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
if (filldir(dirent, tempname, de->namelen, old_pos, le32_to_cpu(de->fnode), DT_UNKNOWN) < 0) {
filp->f_pos = old_pos;
if (!dir_emit(ctx, tempname, de->namelen, le32_to_cpu(de->fnode), DT_UNKNOWN)) {
if (tempname != de->name) kfree(tempname);
hpfs_brelse4(&qbh);
goto out;
}
ctx->pos = next_pos;
if (tempname != de->name) kfree(tempname);
hpfs_brelse4(&qbh);
}
......@@ -322,7 +324,7 @@ const struct file_operations hpfs_dir_ops =
{
.llseek = hpfs_dir_lseek,
.read = generic_read_dir,
.readdir = hpfs_readdir,
.iterate = hpfs_readdir,
.release = hpfs_dir_release,
.fsync = hpfs_file_fsync,
};
......@@ -542,8 +542,8 @@ static const struct file_operations hppfs_file_fops = {
};
struct hppfs_dirent {
void *vfs_dirent;
filldir_t filldir;
struct dir_context ctx;
struct dir_context *caller;
struct dentry *dentry;
};
......@@ -555,34 +555,29 @@ static int hppfs_filldir(void *d, const char *name, int size,
if (file_removed(dirent->dentry, name))
return 0;
return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset,
inode, type);
dirent->caller->pos = dirent->ctx.pos;
return !dir_emit(dirent->caller, name, size, inode, type);
}
static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
static int hppfs_readdir(struct file *file, struct dir_context *ctx)
{
struct hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file;
int (*readdir)(struct file *, void *, filldir_t);
struct hppfs_dirent dirent = ((struct hppfs_dirent)
{ .vfs_dirent = ent,
.filldir = filldir,
.dentry = file->f_path.dentry
});
struct hppfs_dirent d = {
.ctx.actor = hppfs_filldir,
.caller = ctx,
.dentry = file->f_path.dentry
};
int err;
readdir = file_inode(proc_file)->i_fop->readdir;
proc_file->f_pos = file->f_pos;
err = (*readdir)(proc_file, &dirent, hppfs_filldir);
file->f_pos = proc_file->f_pos;
proc_file->f_pos = ctx->pos;
err = iterate_dir(proc_file, &d.ctx);
ctx->pos = d.ctx.pos;
return err;
}
static const struct file_operations hppfs_dir_fops = {
.owner = NULL,
.readdir = hppfs_readdir,
.iterate = hppfs_readdir,
.open = hppfs_dir_open,
.llseek = default_llseek,
.release = hppfs_release,
......
......@@ -78,8 +78,8 @@ int get_acorn_filename(struct iso_directory_record *de,
/*
* This should _really_ be cleaned up some day..
*/
static int do_isofs_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir,
static int do_isofs_readdir(struct inode *inode, struct file *file,
struct dir_context *ctx,
char *tmpname, struct iso_directory_record *tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
......@@ -94,10 +94,10 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
struct iso_directory_record *de;
struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
offset = filp->f_pos & (bufsize - 1);
block = filp->f_pos >> bufbits;
offset = ctx->pos & (bufsize - 1);
block = ctx->pos >> bufbits;
while (filp->f_pos < inode->i_size) {
while (ctx->pos < inode->i_size) {
int de_len;
if (!bh) {
......@@ -108,7 +108,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
de = (struct iso_directory_record *) (bh->b_data + offset);
de_len = *(unsigned char *) de;
de_len = *(unsigned char *)de;
/*
* If the length byte is zero, we should move on to the next
......@@ -119,8 +119,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (de_len == 0) {
brelse(bh);
bh = NULL;
filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
block = filp->f_pos >> bufbits;
ctx->pos = (ctx->pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
block = ctx->pos >> bufbits;
offset = 0;
continue;
}
......@@ -164,16 +164,16 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (de->flags[-sbi->s_high_sierra] & 0x80) {
first_de = 0;
filp->f_pos += de_len;
ctx->pos += de_len;
continue;
}
first_de = 1;
/* Handle the case of the '.' directory */
if (de->name_len[0] == 1 && de->name[0] == 0) {
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
if (!dir_emit_dot(file, ctx))
break;
filp->f_pos += de_len;
ctx->pos += de_len;
continue;
}
......@@ -181,10 +181,9 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
inode_number = parent_ino(filp->f_path.dentry);
if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
if (!dir_emit_dotdot(file, ctx))
break;
filp->f_pos += de_len;
ctx->pos += de_len;
continue;
}
......@@ -198,7 +197,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) ||
(!sbi->s_showassoc &&
(de->flags[-sbi->s_high_sierra] & 4))) {
filp->f_pos += de_len;
ctx->pos += de_len;
continue;
}
......@@ -230,10 +229,10 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
}
if (len > 0) {
if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
if (!dir_emit(ctx, p, len, inode_number, DT_UNKNOWN))
break;
}
filp->f_pos += de_len;
ctx->pos += de_len;
continue;
}
......@@ -247,13 +246,12 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
* handling split directory entries.. The real work is done by
* "do_isofs_readdir()".
*/
static int isofs_readdir(struct file *filp,
void *dirent, filldir_t filldir)
static int isofs_readdir(struct file *file, struct dir_context *ctx)
{
int result;
char *tmpname;
struct iso_directory_record *tmpde;
struct inode *inode = file_inode(filp);
struct inode *inode = file_inode(file);
tmpname = (char *)__get_free_page(GFP_KERNEL);
if (tmpname == NULL)
......@@ -261,7 +259,7 @@ static int isofs_readdir(struct file *filp,
tmpde = (struct iso_directory_record *) (tmpname+1024);
result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
result = do_isofs_readdir(inode, file, ctx, tmpname, tmpde);
free_page((unsigned long) tmpname);
return result;
......@@ -271,7 +269,7 @@ const struct file_operations isofs_dir_operations =
{
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = isofs_readdir,
.iterate = isofs_readdir,
};
/*
......
此差异已折叠。
此差异已折叠。
......@@ -265,5 +265,5 @@ extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key,
extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
ino_t * orig_ino, ino_t new_ino, int flag);
extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
extern int jfs_readdir(struct file *file, struct dir_context *ctx);
#endif /* !_H_JFS_DTREE */
......@@ -1529,7 +1529,7 @@ const struct inode_operations jfs_dir_inode_operations = {
const struct file_operations jfs_dir_operations = {
.read = generic_read_dir,
.readdir = jfs_readdir,
.iterate = jfs_readdir,
.fsync = jfs_fsync,
.unlocked_ioctl = jfs_ioctl,
#ifdef CONFIG_COMPAT
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册