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 ...
This commit is contained in:
Коммит
63580e51bb
|
@ -414,7 +414,7 @@ prototypes:
|
||||||
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
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_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||||
ssize_t (*aio_write) (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 *);
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
||||||
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
long (*compat_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]
|
[mandatory]
|
||||||
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
|
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
|
||||||
in your dentry operations instead.
|
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 (*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_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
|
||||||
ssize_t (*aio_write) (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 *);
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
||||||
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
long (*compat_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
|
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
|
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
|
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)
|
#define kern_addr_valid(addr) (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define io_remap_pfn_range(vma, start, pfn, size, prot) \
|
|
||||||
remap_pfn_range(vma, start, pfn, size, prot)
|
|
||||||
|
|
||||||
#define pte_ERROR(e) \
|
#define pte_ERROR(e) \
|
||||||
printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
|
printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
|
||||||
#define pmd_ERROR(e) \
|
#define pmd_ERROR(e) \
|
||||||
|
|
|
@ -96,6 +96,7 @@ struct osf_dirent {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osf_dirent_callback {
|
struct osf_dirent_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
struct osf_dirent __user *dirent;
|
struct osf_dirent __user *dirent;
|
||||||
long __user *basep;
|
long __user *basep;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
@ -146,17 +147,17 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
struct fd arg = fdget(fd);
|
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)
|
if (!arg.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
buf.dirent = dirent;
|
error = iterate_dir(arg.file, &buf.ctx);
|
||||||
buf.basep = basep;
|
|
||||||
buf.count = count;
|
|
||||||
buf.error = 0;
|
|
||||||
|
|
||||||
error = vfs_readdir(arg.file, osf_filldir, &buf);
|
|
||||||
if (error >= 0)
|
if (error >= 0)
|
||||||
error = buf.error;
|
error = buf.error;
|
||||||
if (count != buf.count)
|
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;
|
base = sparse ? hose->sparse_io_base : hose->dense_io_base;
|
||||||
|
|
||||||
vma->vm_pgoff += base >> PAGE_SHIFT;
|
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,
|
return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
|
||||||
vma->vm_end - vma->vm_start,
|
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'
|
* remap a physical page `pfn' of size `size' with page protection `prot'
|
||||||
* into virtual address `from'
|
* 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>
|
#include <asm-generic/pgtable.h>
|
||||||
|
|
||||||
/* to cope with aliasing VIPT cache */
|
/* to cope with aliasing VIPT cache */
|
||||||
|
|
|
@ -79,8 +79,6 @@ extern unsigned int kobjsize(const void *objp);
|
||||||
* No page table caches to initialise.
|
* No page table caches to initialise.
|
||||||
*/
|
*/
|
||||||
#define pgtable_cache_init() do { } while (0)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
#define io_remap_pfn_range remap_pfn_range
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All 32bit addresses are effectively valid for vmalloc...
|
* 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
|
||||||
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
|
#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)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
|
@ -320,13 +320,6 @@ extern int kern_addr_valid(unsigned long addr);
|
||||||
|
|
||||||
#include <asm-generic/pgtable.h>
|
#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)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
|
@ -362,9 +362,6 @@ typedef pte_t *pte_addr_t;
|
||||||
|
|
||||||
#define kern_addr_valid(addr) (1)
|
#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 (?) */
|
/* No page table caches to initialize (?) */
|
||||||
#define pgtable_cache_init() do { } while(0)
|
#define pgtable_cache_init() do { } while(0)
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,6 @@ extern char empty_zero_page[];
|
||||||
* No page table caches to initialise.
|
* No page table caches to initialise.
|
||||||
*/
|
*/
|
||||||
#define pgtable_cache_init() do { } while (0)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
#define io_remap_pfn_range remap_pfn_range
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All 32bit addresses are effectively valid for vmalloc...
|
* All 32bit addresses are effectively valid for vmalloc...
|
||||||
|
|
|
@ -71,7 +71,6 @@ extern unsigned long empty_zero_page;
|
||||||
* No page table caches to initialise
|
* No page table caches to initialise
|
||||||
*/
|
*/
|
||||||
#define pgtable_cache_init() do { } while (0)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
#define io_remap_pfn_range remap_pfn_range
|
|
||||||
|
|
||||||
#include <asm-generic/pgtable.h>
|
#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) \
|
#define pgd_ERROR(e) \
|
||||||
printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(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 */
|
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 PageSkip(page) (0)
|
||||||
#define kern_addr_valid(addr) (1)
|
#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_TEST_AND_CLEAR_YOUNG
|
||||||
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
||||||
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
#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 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...
|
* All 32bit addresses are effectively valid for vmalloc...
|
||||||
* Sort of meaningless for non-VM targets.
|
* 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))
|
#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 */
|
/* I think this is in case we have page table caches; needed by init/main.c */
|
||||||
#define pgtable_cache_init() do { } while (0)
|
#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 pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3)
|
||||||
#define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE })
|
#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
|
* ZERO_PAGE is a global shared page that is always zero: used
|
||||||
* for zero-mapped memory areas etc..
|
* 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 */
|
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
|
||||||
#define kern_addr_valid(addr) (1)
|
#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_TEST_AND_CLEAR_YOUNG
|
||||||
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
||||||
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
#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 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 */
|
/* MMU-specific headers */
|
||||||
|
|
||||||
#ifdef CONFIG_SUN3
|
#ifdef CONFIG_SUN3
|
||||||
|
|
|
@ -55,9 +55,6 @@ extern unsigned int kobjsize(const void *objp);
|
||||||
*/
|
*/
|
||||||
#define pgtable_cache_init() do { } while (0)
|
#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...
|
* All 32bit addresses are effectively valid for vmalloc...
|
||||||
* Sort of meaningless for non-VM targets.
|
* 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 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
|
* No page table caches to initialise
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,9 +13,6 @@
|
||||||
|
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
|
||||||
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
|
|
||||||
remap_pfn_range(vma, vaddr, pfn, size, prot)
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
extern int mem_init_done;
|
extern int mem_init_done;
|
||||||
#endif
|
#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);
|
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);
|
return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot);
|
||||||
}
|
}
|
||||||
#else
|
#define io_remap_pfn_range io_remap_pfn_range
|
||||||
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
|
|
||||||
remap_pfn_range(vma, vaddr, pfn, size, prot)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
#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 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 MK_IOSPACE_PFN(space, pfn) (pfn)
|
||||||
#define GET_IOSPACE(pfn) 0
|
#define GET_IOSPACE(pfn) 0
|
||||||
#define GET_PFN(pfn) (pfn)
|
#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
|
/* Leave vm_pgoff as-is, the PCI space address is the physical
|
||||||
* address on this platform.
|
* address on this platform.
|
||||||
*/
|
*/
|
||||||
vma->vm_flags |= VM_LOCKED | VM_IO;
|
vma->vm_flags |= VM_LOCKED;
|
||||||
|
|
||||||
prot = pgprot_val(vma->vm_page_prot);
|
prot = pgprot_val(vma->vm_page_prot);
|
||||||
prot &= ~_PAGE_CACHE;
|
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 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>
|
#include <asm-generic/pgtable.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct hpux_dirent {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct getdents_callback {
|
struct getdents_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
struct hpux_dirent __user *current_dir;
|
struct hpux_dirent __user *current_dir;
|
||||||
struct hpux_dirent __user *previous;
|
struct hpux_dirent __user *previous;
|
||||||
int count;
|
int count;
|
||||||
|
@ -110,24 +111,23 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
|
||||||
{
|
{
|
||||||
struct fd arg;
|
struct fd arg;
|
||||||
struct hpux_dirent __user * lastdirent;
|
struct hpux_dirent __user * lastdirent;
|
||||||
struct getdents_callback buf;
|
struct getdents_callback buf = {
|
||||||
|
.ctx.actor = filldir,
|
||||||
|
.current_dir = dirent,
|
||||||
|
.count = count
|
||||||
|
};
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
arg = fdget(fd);
|
arg = fdget(fd);
|
||||||
if (!arg.file)
|
if (!arg.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
buf.current_dir = dirent;
|
error = iterate_dir(arg.file, &buf.ctx);
|
||||||
buf.previous = NULL;
|
|
||||||
buf.count = count;
|
|
||||||
buf.error = 0;
|
|
||||||
|
|
||||||
error = vfs_readdir(arg.file, filldir, &buf);
|
|
||||||
if (error >= 0)
|
if (error >= 0)
|
||||||
error = buf.error;
|
error = buf.error;
|
||||||
lastdirent = buf.previous;
|
lastdirent = buf.previous;
|
||||||
if (lastdirent) {
|
if (lastdirent) {
|
||||||
if (put_user(arg.file->f_pos, &lastdirent->d_off))
|
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
else
|
else
|
||||||
error = count - buf.count;
|
error = count - buf.count;
|
||||||
|
|
|
@ -506,9 +506,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
|
||||||
#endif
|
#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)
|
#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
|
||||||
|
|
||||||
/* We provide our own get_unmapped_area to provide cache coherency */
|
/* 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 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>
|
#include <asm-generic/pgtable.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ const struct file_operations spufs_context_fops = {
|
||||||
.release = spufs_dir_close,
|
.release = spufs_dir_close,
|
||||||
.llseek = dcache_dir_lseek,
|
.llseek = dcache_dir_lseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = dcache_readdir,
|
.iterate = dcache_readdir,
|
||||||
.fsync = noop_fsync,
|
.fsync = noop_fsync,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(spufs_context_fops);
|
EXPORT_SYMBOL_GPL(spufs_context_fops);
|
||||||
|
|
|
@ -58,9 +58,6 @@ extern unsigned long zero_page_mask;
|
||||||
#define __HAVE_COLOR_ZERO_PAGE
|
#define __HAVE_COLOR_ZERO_PAGE
|
||||||
|
|
||||||
/* TODO: s390 cannot support io_remap_pfn_range... */
|
/* 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__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -113,9 +113,6 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
|
||||||
#define pte_clear(mm, addr, xp) \
|
#define pte_clear(mm, addr, xp) \
|
||||||
do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
|
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
|
* 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
|
* 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 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)))
|
#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);
|
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 __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
|
||||||
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
|
#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);
|
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/tlbflush.h>
|
||||||
#include <asm-generic/pgtable.h>
|
#include <asm-generic/pgtable.h>
|
||||||
|
|
|
@ -773,15 +773,6 @@ static int __pci_mmap_make_offset(struct pci_dev *pdev,
|
||||||
return 0;
|
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
|
/* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
|
||||||
* device mapping.
|
* device mapping.
|
||||||
*/
|
*/
|
||||||
|
@ -809,7 +800,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
__pci_mmap_set_flags(dev, vma, mmap_state);
|
|
||||||
__pci_mmap_set_pgprot(dev, vma, mmap_state);
|
__pci_mmap_set_pgprot(dev, vma, mmap_state);
|
||||||
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
|
|
|
@ -362,9 +362,6 @@ do { \
|
||||||
#define kern_addr_valid(addr) (1)
|
#define kern_addr_valid(addr) (1)
|
||||||
#endif /* CONFIG_FLATMEM */
|
#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);
|
extern void vmalloc_sync_all(void);
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#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 __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
|
||||||
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
|
#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
|
* The i386 can't do page protection for execute, and considers that the same
|
||||||
* are read.
|
* are read.
|
||||||
|
|
|
@ -303,13 +303,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
|
||||||
|
|
||||||
#include <asm-generic/pgtable.h>
|
#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)
|
#define pgtable_cache_init() do { } while (0)
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
|
@ -506,9 +506,6 @@ static inline unsigned long pages_to_mb(unsigned long npg)
|
||||||
return npg >> (20 - PAGE_SHIFT);
|
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
|
#if PAGETABLE_LEVELS > 2
|
||||||
static inline int pud_none(pud_t pud)
|
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,
|
extern void update_mmu_cache(struct vm_area_struct * vma,
|
||||||
unsigned long address, pte_t *ptep);
|
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;
|
typedef pte_t *pte_addr_t;
|
||||||
|
|
||||||
#endif /* !defined (__ASSEMBLY__) */
|
#endif /* !defined (__ASSEMBLY__) */
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/loop.h>
|
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
|
MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
|
||||||
|
|
|
@ -63,7 +63,6 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/loop.h>
|
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
@ -76,6 +75,7 @@
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/falloc.h>
|
#include <linux/falloc.h>
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/linux/loop.h
|
* loop.h
|
||||||
*
|
*
|
||||||
* Written by Theodore Ts'o, 3/29/93.
|
* 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_FRAME_BUFFER:
|
||||||
case _DRM_REGISTERS:
|
case _DRM_REGISTERS:
|
||||||
offset = drm_core_get_reg_ofs(dev);
|
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);
|
vma->vm_page_prot = drm_io_prot(map->type, vma);
|
||||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||||
(map->offset + offset) >> PAGE_SHIFT,
|
(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 = dev_priv->mmap_buffer;
|
||||||
buf_priv = buf->dev_private;
|
buf_priv = buf->dev_private;
|
||||||
|
|
||||||
vma->vm_flags |= (VM_IO | VM_DONTCOPY);
|
vma->vm_flags |= VM_DONTCOPY;
|
||||||
|
|
||||||
buf_priv->currently_mapped = I810_BUF_MAPPED;
|
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_private_data = vdev;
|
||||||
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
|
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);
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
|
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,
|
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
|
||||||
vma->vm_end - vma->vm_start,
|
vma->vm_end - vma->vm_start,
|
||||||
vma->vm_page_prot)) {
|
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);
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
|
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,
|
return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
|
||||||
vma->vm_end - vma->vm_start,
|
vma->vm_end - vma->vm_start,
|
||||||
vma->vm_page_prot);
|
vma->vm_page_prot);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
|
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))
|
if (size != resource_size(priv->resource_mem))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
vma->vm_flags |= VM_IO;
|
|
||||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
|
|
||||||
return io_remap_pfn_range(vma, vma->vm_start,
|
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
|
* v9fs_dir_readdir - iterate through a directory
|
||||||
* @filp: opened file structure
|
* @file: opened file structure
|
||||||
* @dirent: directory structure ???
|
* @ctx: actor we feed the entries to
|
||||||
* @filldir: function to populate directory structure ???
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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;
|
struct p9_wstat st;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
|
@ -118,19 +117,19 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
int reclen = 0;
|
int reclen = 0;
|
||||||
struct p9_rdir *rdir;
|
struct p9_rdir *rdir;
|
||||||
|
|
||||||
p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
|
p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
|
||||||
fid = filp->private_data;
|
fid = file->private_data;
|
||||||
|
|
||||||
buflen = fid->clnt->msize - P9_IOHDRSZ;
|
buflen = fid->clnt->msize - P9_IOHDRSZ;
|
||||||
|
|
||||||
rdir = v9fs_alloc_rdir_buf(filp, buflen);
|
rdir = v9fs_alloc_rdir_buf(file, buflen);
|
||||||
if (!rdir)
|
if (!rdir)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (rdir->tail == rdir->head) {
|
if (rdir->tail == rdir->head) {
|
||||||
err = v9fs_file_readn(filp, rdir->buf, NULL,
|
err = v9fs_file_readn(file, rdir->buf, NULL,
|
||||||
buflen, filp->f_pos);
|
buflen, ctx->pos);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -148,51 +147,45 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
}
|
}
|
||||||
reclen = st.size+2;
|
reclen = st.size+2;
|
||||||
|
|
||||||
over = filldir(dirent, st.name, strlen(st.name),
|
over = !dir_emit(ctx, st.name, strlen(st.name),
|
||||||
filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
|
v9fs_qid2ino(&st.qid), dt_type(&st));
|
||||||
|
|
||||||
p9stat_free(&st);
|
p9stat_free(&st);
|
||||||
|
|
||||||
if (over)
|
if (over)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rdir->head += reclen;
|
rdir->head += reclen;
|
||||||
filp->f_pos += reclen;
|
ctx->pos += reclen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v9fs_dir_readdir_dotl - read a directory
|
* v9fs_dir_readdir_dotl - iterate through a directory
|
||||||
* @filp: opened file structure
|
* @file: opened file structure
|
||||||
* @dirent: buffer to fill dirent structures
|
* @ctx: actor we feed the entries to
|
||||||
* @filldir: function to populate dirent structures
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
|
||||||
filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
int over;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
int buflen;
|
int buflen;
|
||||||
struct p9_rdir *rdir;
|
struct p9_rdir *rdir;
|
||||||
struct p9_dirent curdirent;
|
struct p9_dirent curdirent;
|
||||||
u64 oldoffset = 0;
|
|
||||||
|
|
||||||
p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
|
p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
|
||||||
fid = filp->private_data;
|
fid = file->private_data;
|
||||||
|
|
||||||
buflen = fid->clnt->msize - P9_READDIRHDRSZ;
|
buflen = fid->clnt->msize - P9_READDIRHDRSZ;
|
||||||
|
|
||||||
rdir = v9fs_alloc_rdir_buf(filp, buflen);
|
rdir = v9fs_alloc_rdir_buf(file, buflen);
|
||||||
if (!rdir)
|
if (!rdir)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (rdir->tail == rdir->head) {
|
if (rdir->tail == rdir->head) {
|
||||||
err = p9_client_readdir(fid, rdir->buf, buflen,
|
err = p9_client_readdir(fid, rdir->buf, buflen,
|
||||||
filp->f_pos);
|
ctx->pos);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -210,22 +203,13 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* d_off in dirent structure tracks the offset into
|
if (!dir_emit(ctx, curdirent.d_name,
|
||||||
* the next dirent in the dir. However, filldir()
|
strlen(curdirent.d_name),
|
||||||
* expects offset into the current dirent. Hence
|
v9fs_qid2ino(&curdirent.qid),
|
||||||
* while calling filldir send the offset from the
|
curdirent.d_type))
|
||||||
* 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)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
filp->f_pos = curdirent.d_off;
|
ctx->pos = curdirent.d_off;
|
||||||
rdir->head += err;
|
rdir->head += err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +238,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
|
||||||
const struct file_operations v9fs_dir_operations = {
|
const struct file_operations v9fs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.readdir = v9fs_dir_readdir,
|
.iterate = v9fs_dir_readdir,
|
||||||
.open = v9fs_file_open,
|
.open = v9fs_file_open,
|
||||||
.release = v9fs_dir_release,
|
.release = v9fs_dir_release,
|
||||||
};
|
};
|
||||||
|
@ -262,7 +246,7 @@ const struct file_operations v9fs_dir_operations = {
|
||||||
const struct file_operations v9fs_dir_operations_dotl = {
|
const struct file_operations v9fs_dir_operations_dotl = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.readdir = v9fs_dir_readdir_dotl,
|
.iterate = v9fs_dir_readdir_dotl,
|
||||||
.open = v9fs_file_open,
|
.open = v9fs_file_open,
|
||||||
.release = v9fs_dir_release,
|
.release = v9fs_dir_release,
|
||||||
.fsync = v9fs_file_fsync_dotl,
|
.fsync = v9fs_file_fsync_dotl,
|
||||||
|
|
|
@ -17,47 +17,43 @@
|
||||||
static DEFINE_RWLOCK(adfs_dir_lock);
|
static DEFINE_RWLOCK(adfs_dir_lock);
|
||||||
|
|
||||||
static int
|
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 super_block *sb = inode->i_sb;
|
||||||
struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
|
struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
|
||||||
struct object_info obj;
|
struct object_info obj;
|
||||||
struct adfs_dir dir;
|
struct adfs_dir dir;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (filp->f_pos >> 32)
|
if (ctx->pos >> 32)
|
||||||
goto out;
|
return 0;
|
||||||
|
|
||||||
ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
|
ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
return ret;
|
||||||
|
|
||||||
switch ((unsigned long)filp->f_pos) {
|
if (ctx->pos == 0) {
|
||||||
case 0:
|
if (!dir_emit_dot(file, ctx))
|
||||||
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
|
|
||||||
goto free_out;
|
goto free_out;
|
||||||
filp->f_pos += 1;
|
ctx->pos = 1;
|
||||||
|
}
|
||||||
case 1:
|
if (ctx->pos == 1) {
|
||||||
if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
|
if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
|
||||||
goto free_out;
|
goto free_out;
|
||||||
filp->f_pos += 1;
|
ctx->pos = 2;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read_lock(&adfs_dir_lock);
|
read_lock(&adfs_dir_lock);
|
||||||
|
|
||||||
ret = ops->setpos(&dir, filp->f_pos - 2);
|
ret = ops->setpos(&dir, ctx->pos - 2);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto unlock_out;
|
goto unlock_out;
|
||||||
while (ops->getnext(&dir, &obj) == 0) {
|
while (ops->getnext(&dir, &obj) == 0) {
|
||||||
if (filldir(dirent, obj.name, obj.name_len,
|
if (!dir_emit(ctx, obj.name, obj.name_len,
|
||||||
filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
|
obj.file_id, DT_UNKNOWN))
|
||||||
goto unlock_out;
|
break;
|
||||||
filp->f_pos += 1;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_out:
|
unlock_out:
|
||||||
|
@ -65,8 +61,6 @@ unlock_out:
|
||||||
|
|
||||||
free_out:
|
free_out:
|
||||||
ops->free(&dir);
|
ops->free(&dir);
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +186,7 @@ out:
|
||||||
const struct file_operations adfs_dir_operations = {
|
const struct file_operations adfs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.readdir = adfs_readdir,
|
.iterate = adfs_readdir,
|
||||||
.fsync = generic_file_fsync,
|
.fsync = generic_file_fsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
|
|
||||||
#include "affs.h"
|
#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 = {
|
const struct file_operations affs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.readdir = affs_readdir,
|
.iterate = affs_readdir,
|
||||||
.fsync = affs_file_fsync,
|
.fsync = affs_file_fsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,52 +40,35 @@ const struct inode_operations affs_dir_inode_operations = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
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 super_block *sb = inode->i_sb;
|
||||||
struct buffer_head *dir_bh;
|
struct buffer_head *dir_bh = NULL;
|
||||||
struct buffer_head *fh_bh;
|
struct buffer_head *fh_bh = NULL;
|
||||||
unsigned char *name;
|
unsigned char *name;
|
||||||
int namelen;
|
int namelen;
|
||||||
u32 i;
|
u32 i;
|
||||||
int hash_pos;
|
int hash_pos;
|
||||||
int chain_pos;
|
int chain_pos;
|
||||||
u32 f_pos;
|
|
||||||
u32 ino;
|
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;
|
if (ctx->pos < 2) {
|
||||||
res = -EIO;
|
file->private_data = (void *)0;
|
||||||
dir_bh = NULL;
|
if (!dir_emit_dots(file, ctx))
|
||||||
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)
|
|
||||||
return 0;
|
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);
|
affs_lock_dir(inode);
|
||||||
chain_pos = (f_pos - 2) & 0xffff;
|
chain_pos = (ctx->pos - 2) & 0xffff;
|
||||||
hash_pos = (f_pos - 2) >> 16;
|
hash_pos = (ctx->pos - 2) >> 16;
|
||||||
if (chain_pos == 0xffff) {
|
if (chain_pos == 0xffff) {
|
||||||
affs_warning(sb, "readdir", "More than 65535 entries in chain");
|
affs_warning(sb, "readdir", "More than 65535 entries in chain");
|
||||||
chain_pos = 0;
|
chain_pos = 0;
|
||||||
hash_pos++;
|
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);
|
dir_bh = affs_bread(sb, inode->i_ino);
|
||||||
if (!dir_bh)
|
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(),
|
/* If the directory hasn't changed since the last call to readdir(),
|
||||||
* we can jump directly to where we left off.
|
* we can jump directly to where we left off.
|
||||||
*/
|
*/
|
||||||
ino = (u32)(long)filp->private_data;
|
ino = (u32)(long)file->private_data;
|
||||||
if (ino && filp->f_version == inode->i_version) {
|
if (ino && file->f_version == inode->i_version) {
|
||||||
pr_debug("AFFS: readdir() left off=%d\n", ino);
|
pr_debug("AFFS: readdir() left off=%d\n", ino);
|
||||||
goto inside;
|
goto inside;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +88,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
fh_bh = affs_bread(sb, ino);
|
fh_bh = affs_bread(sb, ino);
|
||||||
if (!fh_bh) {
|
if (!fh_bh) {
|
||||||
affs_error(sb, "readdir","Cannot read block %d", i);
|
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);
|
ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
|
||||||
affs_brelse(fh_bh);
|
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]);
|
ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
|
||||||
if (!ino)
|
if (!ino)
|
||||||
continue;
|
continue;
|
||||||
f_pos = (hash_pos << 16) + 2;
|
ctx->pos = (hash_pos << 16) + 2;
|
||||||
inside:
|
inside:
|
||||||
do {
|
do {
|
||||||
fh_bh = affs_bread(sb, ino);
|
fh_bh = affs_bread(sb, ino);
|
||||||
if (!fh_bh) {
|
if (!fh_bh) {
|
||||||
affs_error(sb, "readdir","Cannot read block %d", ino);
|
affs_error(sb, "readdir","Cannot read block %d", ino);
|
||||||
goto readdir_done;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
|
namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
|
||||||
name = AFFS_TAIL(sb, fh_bh)->name + 1;
|
name = AFFS_TAIL(sb, fh_bh)->name + 1;
|
||||||
pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
|
pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
|
||||||
namelen, name, ino, hash_pos, f_pos);
|
namelen, name, ino, hash_pos, (u32)ctx->pos);
|
||||||
if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
|
if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
|
||||||
goto readdir_done;
|
goto readdir_done;
|
||||||
stored++;
|
ctx->pos++;
|
||||||
f_pos++;
|
|
||||||
ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
|
ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
|
||||||
affs_brelse(fh_bh);
|
affs_brelse(fh_bh);
|
||||||
fh_bh = NULL;
|
fh_bh = NULL;
|
||||||
} while (ino);
|
} while (ino);
|
||||||
}
|
}
|
||||||
readdir_done:
|
readdir_done:
|
||||||
filp->f_pos = f_pos;
|
file->f_version = inode->i_version;
|
||||||
filp->f_version = inode->i_version;
|
file->private_data = (void *)(long)ino;
|
||||||
filp->private_data = (void *)(long)ino;
|
|
||||||
res = stored;
|
|
||||||
|
|
||||||
readdir_out:
|
readdir_out:
|
||||||
affs_brelse(dir_bh);
|
affs_brelse(dir_bh);
|
||||||
affs_brelse(fh_bh);
|
affs_brelse(fh_bh);
|
||||||
affs_unlock_dir(inode);
|
affs_unlock_dir(inode);
|
||||||
pr_debug("AFFS: readdir()=%d\n", stored);
|
return 0;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
99
fs/afs/dir.c
99
fs/afs/dir.c
|
@ -22,7 +22,7 @@
|
||||||
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
static int afs_dir_open(struct inode *inode, struct file *file);
|
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_revalidate(struct dentry *dentry, unsigned int flags);
|
||||||
static int afs_d_delete(const struct dentry *dentry);
|
static int afs_d_delete(const struct dentry *dentry);
|
||||||
static void afs_d_release(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 = {
|
const struct file_operations afs_dir_file_operations = {
|
||||||
.open = afs_dir_open,
|
.open = afs_dir_open,
|
||||||
.release = afs_release,
|
.release = afs_release,
|
||||||
.readdir = afs_readdir,
|
.iterate = afs_readdir,
|
||||||
.lock = afs_lock,
|
.lock = afs_lock,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
|
@ -119,9 +119,9 @@ struct afs_dir_page {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct afs_lookup_cookie {
|
struct afs_lookup_cookie {
|
||||||
|
struct dir_context ctx;
|
||||||
struct afs_fid fid;
|
struct afs_fid fid;
|
||||||
const char *name;
|
struct qstr name;
|
||||||
size_t nlen;
|
|
||||||
int found;
|
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
|
* 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,
|
union afs_dir_block *block,
|
||||||
unsigned blkoff,
|
unsigned blkoff)
|
||||||
void *cookie,
|
|
||||||
filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
union afs_dirent *dire;
|
union afs_dirent *dire;
|
||||||
unsigned offset, next, curr;
|
unsigned offset, next, curr;
|
||||||
size_t nlen;
|
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 */
|
/* walk through the block, an entry at a time */
|
||||||
for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
|
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",
|
_debug("ENT[%Zu.%u]: unused",
|
||||||
blkoff / sizeof(union afs_dir_block), offset);
|
blkoff / sizeof(union afs_dir_block), offset);
|
||||||
if (offset >= curr)
|
if (offset >= curr)
|
||||||
*fpos = blkoff +
|
ctx->pos = blkoff +
|
||||||
next * sizeof(union afs_dirent);
|
next * sizeof(union afs_dirent);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -302,19 +300,15 @@ static int afs_dir_iterate_block(unsigned *fpos,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* found the next entry */
|
/* found the next entry */
|
||||||
ret = filldir(cookie,
|
if (!dir_emit(ctx, dire->u.name, nlen,
|
||||||
dire->u.name,
|
|
||||||
nlen,
|
|
||||||
blkoff + offset * sizeof(union afs_dirent),
|
|
||||||
ntohl(dire->u.vnode),
|
ntohl(dire->u.vnode),
|
||||||
filldir == afs_lookup_filldir ?
|
ctx->actor == afs_lookup_filldir ?
|
||||||
ntohl(dire->u.unique) : DT_UNKNOWN);
|
ntohl(dire->u.unique) : DT_UNKNOWN)) {
|
||||||
if (ret < 0) {
|
|
||||||
_leave(" = 0 [full]");
|
_leave(" = 0 [full]");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*fpos = blkoff + next * sizeof(union afs_dirent);
|
ctx->pos = blkoff + next * sizeof(union afs_dirent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_leave(" = 1 [more]");
|
_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
|
* 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,
|
static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct key *key)
|
struct key *key)
|
||||||
{
|
{
|
||||||
union afs_dir_block *dblock;
|
union afs_dir_block *dblock;
|
||||||
struct afs_dir_page *dbuf;
|
struct afs_dir_page *dbuf;
|
||||||
|
@ -333,7 +327,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
|
||||||
unsigned blkoff, limit;
|
unsigned blkoff, limit;
|
||||||
int ret;
|
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)) {
|
if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
|
||||||
_leave(" = -ESTALE");
|
_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 */
|
/* round the file position up to the next entry boundary */
|
||||||
*fpos += sizeof(union afs_dirent) - 1;
|
ctx->pos += sizeof(union afs_dirent) - 1;
|
||||||
*fpos &= ~(sizeof(union afs_dirent) - 1);
|
ctx->pos &= ~(sizeof(union afs_dirent) - 1);
|
||||||
|
|
||||||
/* walk through the blocks in sequence */
|
/* walk through the blocks in sequence */
|
||||||
ret = 0;
|
ret = 0;
|
||||||
while (*fpos < dir->i_size) {
|
while (ctx->pos < dir->i_size) {
|
||||||
blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1);
|
blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
|
||||||
|
|
||||||
/* fetch the appropriate page from the directory */
|
/* fetch the appropriate page from the directory */
|
||||||
page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
|
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 {
|
do {
|
||||||
dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
|
dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
|
||||||
sizeof(union afs_dir_block)];
|
sizeof(union afs_dir_block)];
|
||||||
ret = afs_dir_iterate_block(fpos, dblock, blkoff,
|
ret = afs_dir_iterate_block(ctx, dblock, blkoff);
|
||||||
cookie, filldir);
|
|
||||||
if (ret != 1) {
|
if (ret != 1) {
|
||||||
afs_dir_put_page(page);
|
afs_dir_put_page(page);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -373,7 +366,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
|
||||||
|
|
||||||
blkoff += sizeof(union afs_dir_block);
|
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);
|
afs_dir_put_page(page);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -387,23 +380,10 @@ out:
|
||||||
/*
|
/*
|
||||||
* read an AFS directory
|
* 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;
|
return afs_dir_iterate(file_inode(file),
|
||||||
int ret;
|
ctx, file->private_data);
|
||||||
|
|
||||||
_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -416,15 +396,16 @@ static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
|
||||||
{
|
{
|
||||||
struct afs_lookup_cookie *cookie = _cookie;
|
struct afs_lookup_cookie *cookie = _cookie;
|
||||||
|
|
||||||
_enter("{%s,%Zu},%s,%u,,%llu,%u",
|
_enter("{%s,%u},%s,%u,,%llu,%u",
|
||||||
cookie->name, cookie->nlen, name, nlen,
|
cookie->name.name, cookie->name.len, name, nlen,
|
||||||
(unsigned long long) ino, dtype);
|
(unsigned long long) ino, dtype);
|
||||||
|
|
||||||
/* insanity checks first */
|
/* insanity checks first */
|
||||||
BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
|
BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
|
||||||
BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
|
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]");
|
_leave(" = 0 [no]");
|
||||||
return 0;
|
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,
|
static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
struct afs_fid *fid, struct key *key)
|
struct afs_fid *fid, struct key *key)
|
||||||
{
|
{
|
||||||
struct afs_lookup_cookie cookie;
|
struct afs_super_info *as = dir->i_sb->s_fs_info;
|
||||||
struct afs_super_info *as;
|
struct afs_lookup_cookie cookie = {
|
||||||
unsigned fpos;
|
.ctx.actor = afs_lookup_filldir,
|
||||||
|
.name = dentry->d_name,
|
||||||
|
.fid.vid = as->volume->vid
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name);
|
_enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name);
|
||||||
|
|
||||||
as = dir->i_sb->s_fs_info;
|
|
||||||
|
|
||||||
/* search the directory */
|
/* search the directory */
|
||||||
cookie.name = dentry->d_name.name;
|
ret = afs_dir_iterate(dir, &cookie.ctx, key);
|
||||||
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);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
_leave(" = %d [iter]", ret);
|
_leave(" = %d [iter]", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -41,7 +41,7 @@ const struct file_operations autofs4_root_operations = {
|
||||||
.open = dcache_dir_open,
|
.open = dcache_dir_open,
|
||||||
.release = dcache_dir_close,
|
.release = dcache_dir_close,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = dcache_readdir,
|
.iterate = dcache_readdir,
|
||||||
.llseek = dcache_dir_lseek,
|
.llseek = dcache_dir_lseek,
|
||||||
.unlocked_ioctl = autofs4_root_ioctl,
|
.unlocked_ioctl = autofs4_root_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
@ -53,7 +53,7 @@ const struct file_operations autofs4_dir_operations = {
|
||||||
.open = autofs4_dir_open,
|
.open = autofs4_dir_open,
|
||||||
.release = dcache_dir_close,
|
.release = dcache_dir_close,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = dcache_readdir,
|
.iterate = dcache_readdir,
|
||||||
.llseek = dcache_dir_lseek,
|
.llseek = dcache_dir_lseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||||
return -EIO;
|
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;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ static const struct file_operations bad_file_ops =
|
||||||
.write = bad_file_write,
|
.write = bad_file_write,
|
||||||
.aio_read = bad_file_aio_read,
|
.aio_read = bad_file_aio_read,
|
||||||
.aio_write = bad_file_aio_write,
|
.aio_write = bad_file_aio_write,
|
||||||
.readdir = bad_file_readdir,
|
.iterate = bad_file_readdir,
|
||||||
.poll = bad_file_poll,
|
.poll = bad_file_poll,
|
||||||
.unlocked_ioctl = bad_file_unlocked_ioctl,
|
.unlocked_ioctl = bad_file_unlocked_ioctl,
|
||||||
.compat_ioctl = bad_file_compat_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 */
|
/* The units the vfs expects inode->i_blocks to be in */
|
||||||
#define VFS_BLOCK_SIZE 512
|
#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_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||||
static int befs_readpage(struct file *file, struct page *page);
|
static int befs_readpage(struct file *file, struct page *page);
|
||||||
static sector_t befs_bmap(struct address_space *mapping, sector_t block);
|
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 = {
|
static const struct file_operations befs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = befs_readdir,
|
.iterate = befs_readdir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,9 +211,9 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct super_block *sb = inode->i_sb;
|
||||||
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
|
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
|
||||||
befs_off_t value;
|
befs_off_t value;
|
||||||
|
@ -221,15 +221,14 @@ befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
size_t keysize;
|
size_t keysize;
|
||||||
unsigned char d_type;
|
unsigned char d_type;
|
||||||
char keybuf[BEFS_NAME_LEN + 1];
|
char keybuf[BEFS_NAME_LEN + 1];
|
||||||
char *nlsname;
|
const char *dirname = file->f_path.dentry->d_name.name;
|
||||||
int nlsnamelen;
|
|
||||||
const char *dirname = filp->f_path.dentry->d_name.name;
|
|
||||||
|
|
||||||
befs_debug(sb, "---> befs_readdir() "
|
befs_debug(sb, "---> befs_readdir() "
|
||||||
"name %s, inode %ld, filp->f_pos %Ld",
|
"name %s, inode %ld, ctx->pos %Ld",
|
||||||
dirname, inode->i_ino, filp->f_pos);
|
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);
|
keybuf, &keysize, &value);
|
||||||
|
|
||||||
if (result == BEFS_ERR) {
|
if (result == BEFS_ERR) {
|
||||||
|
@ -251,24 +250,29 @@ befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
/* Convert to NLS */
|
/* Convert to NLS */
|
||||||
if (BEFS_SB(sb)->nls) {
|
if (BEFS_SB(sb)->nls) {
|
||||||
|
char *nlsname;
|
||||||
|
int nlsnamelen;
|
||||||
result =
|
result =
|
||||||
befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
|
befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
befs_debug(sb, "<--- befs_readdir() ERROR");
|
befs_debug(sb, "<--- befs_readdir() ERROR");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos,
|
if (!dir_emit(ctx, nlsname, nlsnamelen,
|
||||||
(ino_t) value, d_type);
|
(ino_t) value, d_type)) {
|
||||||
|
kfree(nlsname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
kfree(nlsname);
|
kfree(nlsname);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
result = filldir(dirent, keybuf, keysize, filp->f_pos,
|
if (!dir_emit(ctx, keybuf, keysize,
|
||||||
(ino_t) value, d_type);
|
(ino_t) value, d_type))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (!result)
|
ctx->pos++;
|
||||||
filp->f_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
35
fs/bfs/dir.c
35
fs/bfs/dir.c
|
@ -26,58 +26,51 @@ static struct buffer_head *bfs_find_entry(struct inode *dir,
|
||||||
const unsigned char *name, int namelen,
|
const unsigned char *name, int namelen,
|
||||||
struct bfs_dirent **res_dir);
|
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 inode *dir = file_inode(f);
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct bfs_dirent *de;
|
struct bfs_dirent *de;
|
||||||
struct bfs_sb_info *info = BFS_SB(dir->i_sb);
|
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int block;
|
int block;
|
||||||
|
|
||||||
mutex_lock(&info->bfs_lock);
|
if (ctx->pos & (BFS_DIRENT_SIZE - 1)) {
|
||||||
|
|
||||||
if (f->f_pos & (BFS_DIRENT_SIZE - 1)) {
|
|
||||||
printf("Bad f_pos=%08lx for %s:%08lx\n",
|
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);
|
dir->i_sb->s_id, dir->i_ino);
|
||||||
mutex_unlock(&info->bfs_lock);
|
return -EINVAL;
|
||||||
return -EBADF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (f->f_pos < dir->i_size) {
|
while (ctx->pos < dir->i_size) {
|
||||||
offset = f->f_pos & (BFS_BSIZE - 1);
|
offset = ctx->pos & (BFS_BSIZE - 1);
|
||||||
block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS);
|
block = BFS_I(dir)->i_sblock + (ctx->pos >> BFS_BSIZE_BITS);
|
||||||
bh = sb_bread(dir->i_sb, block);
|
bh = sb_bread(dir->i_sb, block);
|
||||||
if (!bh) {
|
if (!bh) {
|
||||||
f->f_pos += BFS_BSIZE - offset;
|
ctx->pos += BFS_BSIZE - offset;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
de = (struct bfs_dirent *)(bh->b_data + offset);
|
de = (struct bfs_dirent *)(bh->b_data + offset);
|
||||||
if (de->ino) {
|
if (de->ino) {
|
||||||
int size = strnlen(de->name, BFS_NAMELEN);
|
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),
|
le16_to_cpu(de->ino),
|
||||||
DT_UNKNOWN) < 0) {
|
DT_UNKNOWN)) {
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
mutex_unlock(&info->bfs_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += BFS_DIRENT_SIZE;
|
offset += BFS_DIRENT_SIZE;
|
||||||
f->f_pos += BFS_DIRENT_SIZE;
|
ctx->pos += BFS_DIRENT_SIZE;
|
||||||
} while ((offset < BFS_BSIZE) && (f->f_pos < dir->i_size));
|
} while ((offset < BFS_BSIZE) && (ctx->pos < dir->i_size));
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
mutex_unlock(&info->bfs_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct file_operations bfs_dir_operations = {
|
const struct file_operations bfs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = bfs_readdir,
|
.iterate = bfs_readdir,
|
||||||
.fsync = generic_file_fsync,
|
.fsync = generic_file_fsync,
|
||||||
.llseek = generic_file_llseek,
|
.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
|
* btrfs_readdir_delayed_dir_index - read dir info stored in the delayed tree
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
|
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
|
||||||
filldir_t filldir,
|
|
||||||
struct list_head *ins_list)
|
struct list_head *ins_list)
|
||||||
{
|
{
|
||||||
struct btrfs_dir_item *di;
|
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_for_each_entry_safe(curr, next, ins_list, readdir_list) {
|
||||||
list_del(&curr->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))
|
if (atomic_dec_and_test(&curr->refs))
|
||||||
kfree(curr);
|
kfree(curr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
filp->f_pos = curr->key.offset;
|
ctx->pos = curr->key.offset;
|
||||||
|
|
||||||
di = (struct btrfs_dir_item *)curr->data;
|
di = (struct btrfs_dir_item *)curr->data;
|
||||||
name = (char *)(di + 1);
|
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];
|
d_type = btrfs_filetype_table[di->type];
|
||||||
btrfs_disk_key_to_cpu(&location, &di->location);
|
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);
|
location.objectid, d_type);
|
||||||
|
|
||||||
if (atomic_dec_and_test(&curr->refs))
|
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);
|
struct list_head *del_list);
|
||||||
int btrfs_should_delete_dir_index(struct list_head *del_list,
|
int btrfs_should_delete_dir_index(struct list_head *del_list,
|
||||||
u64 index);
|
u64 index);
|
||||||
int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
|
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
|
||||||
filldir_t filldir,
|
|
||||||
struct list_head *ins_list);
|
struct list_head *ins_list);
|
||||||
|
|
||||||
/* for init */
|
/* 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
|
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,
|
static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
|
||||||
filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_item *item;
|
struct btrfs_item *item;
|
||||||
struct btrfs_dir_item *di;
|
struct btrfs_dir_item *di;
|
||||||
|
@ -5161,29 +5160,15 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||||
char tmp_name[32];
|
char tmp_name[32];
|
||||||
char *name_ptr;
|
char *name_ptr;
|
||||||
int name_len;
|
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 */
|
/* FIXME, use a real flag for deciding about the key type */
|
||||||
if (root->fs_info->tree_root == root)
|
if (root->fs_info->tree_root == root)
|
||||||
key_type = BTRFS_DIR_ITEM_KEY;
|
key_type = BTRFS_DIR_ITEM_KEY;
|
||||||
|
|
||||||
/* special case for "." */
|
if (!dir_emit_dots(file, ctx))
|
||||||
if (filp->f_pos == 0) {
|
return 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;
|
|
||||||
}
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -5197,7 +5182,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_set_key_type(&key, key_type);
|
btrfs_set_key_type(&key, key_type);
|
||||||
key.offset = filp->f_pos;
|
key.offset = ctx->pos;
|
||||||
key.objectid = btrfs_ino(inode);
|
key.objectid = btrfs_ino(inode);
|
||||||
|
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
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;
|
break;
|
||||||
if (btrfs_key_type(&found_key) != key_type)
|
if (btrfs_key_type(&found_key) != key_type)
|
||||||
break;
|
break;
|
||||||
if (found_key.offset < filp->f_pos)
|
if (found_key.offset < ctx->pos)
|
||||||
goto next;
|
goto next;
|
||||||
if (key_type == BTRFS_DIR_INDEX_KEY &&
|
if (key_type == BTRFS_DIR_INDEX_KEY &&
|
||||||
btrfs_should_delete_dir_index(&del_list,
|
btrfs_should_delete_dir_index(&del_list,
|
||||||
found_key.offset))
|
found_key.offset))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
filp->f_pos = found_key.offset;
|
ctx->pos = found_key.offset;
|
||||||
is_curr = 1;
|
is_curr = 1;
|
||||||
|
|
||||||
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
|
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;
|
over = 0;
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
over = filldir(dirent, name_ptr, name_len,
|
over = !dir_emit(ctx, name_ptr, name_len,
|
||||||
found_key.offset, location.objectid,
|
location.objectid, d_type);
|
||||||
d_type);
|
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
if (name_ptr != tmp_name)
|
if (name_ptr != tmp_name)
|
||||||
|
@ -5295,9 +5279,8 @@ next:
|
||||||
|
|
||||||
if (key_type == BTRFS_DIR_INDEX_KEY) {
|
if (key_type == BTRFS_DIR_INDEX_KEY) {
|
||||||
if (is_curr)
|
if (is_curr)
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
|
ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
|
||||||
&ins_list);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto nopos;
|
goto nopos;
|
||||||
}
|
}
|
||||||
|
@ -5308,9 +5291,9 @@ next:
|
||||||
* 32-bit glibc will use getdents64, but then strtol -
|
* 32-bit glibc will use getdents64, but then strtol -
|
||||||
* so the last number we can serve is this.
|
* so the last number we can serve is this.
|
||||||
*/
|
*/
|
||||||
filp->f_pos = 0x7fffffff;
|
ctx->pos = 0x7fffffff;
|
||||||
else
|
else
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
nopos:
|
nopos:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err:
|
err:
|
||||||
|
@ -8731,7 +8714,7 @@ static const struct inode_operations btrfs_dir_ro_inode_operations = {
|
||||||
static const struct file_operations btrfs_dir_file_operations = {
|
static const struct file_operations btrfs_dir_file_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = btrfs_real_readdir,
|
.iterate = btrfs_real_readdir,
|
||||||
.unlocked_ioctl = btrfs_ioctl,
|
.unlocked_ioctl = btrfs_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = btrfs_ioctl,
|
.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
|
* defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
|
||||||
* the MDS if/when the directory is modified).
|
* the MDS if/when the directory is modified).
|
||||||
*/
|
*/
|
||||||
static int __dcache_readdir(struct file *filp,
|
static int __dcache_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void *dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
struct ceph_file_info *fi = filp->private_data;
|
struct ceph_file_info *fi = file->private_data;
|
||||||
struct dentry *parent = filp->f_dentry;
|
struct dentry *parent = file->f_dentry;
|
||||||
struct inode *dir = parent->d_inode;
|
struct inode *dir = parent->d_inode;
|
||||||
struct list_head *p;
|
struct list_head *p;
|
||||||
struct dentry *dentry, *last;
|
struct dentry *dentry, *last;
|
||||||
|
@ -126,14 +125,14 @@ static int __dcache_readdir(struct file *filp,
|
||||||
last = fi->dentry;
|
last = fi->dentry;
|
||||||
fi->dentry = NULL;
|
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);
|
last);
|
||||||
|
|
||||||
spin_lock(&parent->d_lock);
|
spin_lock(&parent->d_lock);
|
||||||
|
|
||||||
/* start at beginning? */
|
/* start at beginning? */
|
||||||
if (filp->f_pos == 2 || last == NULL ||
|
if (ctx->pos == 2 || last == NULL ||
|
||||||
filp->f_pos < ceph_dentry(last)->offset) {
|
ctx->pos < ceph_dentry(last)->offset) {
|
||||||
if (list_empty(&parent->d_subdirs))
|
if (list_empty(&parent->d_subdirs))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
p = parent->d_subdirs.prev;
|
p = parent->d_subdirs.prev;
|
||||||
|
@ -157,11 +156,11 @@ more:
|
||||||
if (!d_unhashed(dentry) && dentry->d_inode &&
|
if (!d_unhashed(dentry) && dentry->d_inode &&
|
||||||
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
|
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
|
||||||
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
|
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
|
||||||
filp->f_pos <= di->offset)
|
ctx->pos <= di->offset)
|
||||||
break;
|
break;
|
||||||
dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
|
dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
|
||||||
dentry->d_name.len, dentry->d_name.name, di->offset,
|
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" : "");
|
!dentry->d_inode ? " null" : "");
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
p = p->prev;
|
p = p->prev;
|
||||||
|
@ -173,29 +172,27 @@ more:
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&parent->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);
|
dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
|
||||||
filp->f_pos = di->offset;
|
ctx->pos = di->offset;
|
||||||
err = filldir(dirent, dentry->d_name.name,
|
if (!dir_emit(ctx, dentry->d_name.name,
|
||||||
dentry->d_name.len, di->offset,
|
dentry->d_name.len,
|
||||||
ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
|
ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
|
||||||
dentry->d_inode->i_mode >> 12);
|
dentry->d_inode->i_mode >> 12)) {
|
||||||
|
if (last) {
|
||||||
if (last) {
|
|
||||||
if (err < 0) {
|
|
||||||
/* remember our position */
|
/* remember our position */
|
||||||
fi->dentry = last;
|
fi->dentry = last;
|
||||||
fi->next_offset = di->offset;
|
fi->next_offset = di->offset;
|
||||||
} else {
|
|
||||||
dput(last);
|
|
||||||
}
|
}
|
||||||
|
dput(dentry);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
dput(last);
|
||||||
last = dentry;
|
last = dentry;
|
||||||
|
|
||||||
if (err < 0)
|
ctx->pos++;
|
||||||
goto out;
|
|
||||||
|
|
||||||
filp->f_pos++;
|
|
||||||
|
|
||||||
/* make sure a dentry wasn't dropped while we didn't have parent lock */
|
/* make sure a dentry wasn't dropped while we didn't have parent lock */
|
||||||
if (!ceph_dir_is_complete(dir)) {
|
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;
|
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 ceph_file_info *fi = file->private_data;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||||
unsigned frag = fpos_frag(filp->f_pos);
|
unsigned frag = fpos_frag(ctx->pos);
|
||||||
int off = fpos_off(filp->f_pos);
|
int off = fpos_off(ctx->pos);
|
||||||
int err;
|
int err;
|
||||||
u32 ftype;
|
u32 ftype;
|
||||||
struct ceph_mds_reply_info_parsed *rinfo;
|
struct ceph_mds_reply_info_parsed *rinfo;
|
||||||
const int max_entries = fsc->mount_options->max_readdir;
|
const int max_entries = fsc->mount_options->max_readdir;
|
||||||
const int max_bytes = fsc->mount_options->max_readdir_bytes;
|
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)
|
if (fi->flags & CEPH_F_ATEND)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* always start with . and .. */
|
/* always start with . and .. */
|
||||||
if (filp->f_pos == 0) {
|
if (ctx->pos == 0) {
|
||||||
/* note dir version at start of readdir so we can tell
|
/* note dir version at start of readdir so we can tell
|
||||||
* if any dentries get dropped */
|
* if any dentries get dropped */
|
||||||
fi->dir_release_count = atomic_read(&ci->i_release_count);
|
fi->dir_release_count = atomic_read(&ci->i_release_count);
|
||||||
|
|
||||||
dout("readdir off 0 -> '.'\n");
|
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),
|
ceph_translate_ino(inode->i_sb, inode->i_ino),
|
||||||
inode->i_mode >> 12) < 0)
|
inode->i_mode >> 12))
|
||||||
return 0;
|
return 0;
|
||||||
filp->f_pos = 1;
|
ctx->pos = 1;
|
||||||
off = 1;
|
off = 1;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 1) {
|
if (ctx->pos == 1) {
|
||||||
ino_t ino = parent_ino(filp->f_dentry);
|
ino_t ino = parent_ino(file->f_dentry);
|
||||||
dout("readdir off 1 -> '..'\n");
|
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),
|
ceph_translate_ino(inode->i_sb, ino),
|
||||||
inode->i_mode >> 12) < 0)
|
inode->i_mode >> 12))
|
||||||
return 0;
|
return 0;
|
||||||
filp->f_pos = 2;
|
ctx->pos = 2;
|
||||||
off = 2;
|
off = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* can we use the dcache? */
|
/* can we use the dcache? */
|
||||||
spin_lock(&ci->i_ceph_lock);
|
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_test_mount_opt(fsc, NOASYNCREADDIR) &&
|
||||||
ceph_snap(inode) != CEPH_SNAPDIR &&
|
ceph_snap(inode) != CEPH_SNAPDIR &&
|
||||||
__ceph_dir_is_complete(ci) &&
|
__ceph_dir_is_complete(ci) &&
|
||||||
__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
|
__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
|
||||||
spin_unlock(&ci->i_ceph_lock);
|
spin_unlock(&ci->i_ceph_lock);
|
||||||
err = __dcache_readdir(filp, dirent, filldir);
|
err = __dcache_readdir(file, ctx);
|
||||||
if (err != -EAGAIN)
|
if (err != -EAGAIN)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
|
@ -327,7 +324,7 @@ more:
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
req->r_inode = inode;
|
req->r_inode = inode;
|
||||||
ihold(inode);
|
ihold(inode);
|
||||||
req->r_dentry = dget(filp->f_dentry);
|
req->r_dentry = dget(file->f_dentry);
|
||||||
/* hints to request -> mds selection code */
|
/* hints to request -> mds selection code */
|
||||||
req->r_direct_mode = USE_AUTH_MDS;
|
req->r_direct_mode = USE_AUTH_MDS;
|
||||||
req->r_direct_hash = ceph_frag_value(frag);
|
req->r_direct_hash = ceph_frag_value(frag);
|
||||||
|
@ -379,15 +376,16 @@ more:
|
||||||
rinfo = &fi->last_readdir->r_reply_info;
|
rinfo = &fi->last_readdir->r_reply_info;
|
||||||
dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
|
dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
|
||||||
rinfo->dir_nr, off, fi->offset);
|
rinfo->dir_nr, off, fi->offset);
|
||||||
|
|
||||||
|
ctx->pos = ceph_make_fpos(frag, off);
|
||||||
while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
|
while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
|
||||||
u64 pos = ceph_make_fpos(frag, off);
|
|
||||||
struct ceph_mds_reply_inode *in =
|
struct ceph_mds_reply_inode *in =
|
||||||
rinfo->dir_in[off - fi->offset].in;
|
rinfo->dir_in[off - fi->offset].in;
|
||||||
struct ceph_vino vino;
|
struct ceph_vino vino;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
|
|
||||||
dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
|
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_len[off - fi->offset],
|
||||||
rinfo->dir_dname[off - fi->offset], in);
|
rinfo->dir_dname[off - fi->offset], in);
|
||||||
BUG_ON(!in);
|
BUG_ON(!in);
|
||||||
|
@ -395,16 +393,15 @@ more:
|
||||||
vino.ino = le64_to_cpu(in->ino);
|
vino.ino = le64_to_cpu(in->ino);
|
||||||
vino.snap = le64_to_cpu(in->snapid);
|
vino.snap = le64_to_cpu(in->snapid);
|
||||||
ino = ceph_vino_to_ino(vino);
|
ino = ceph_vino_to_ino(vino);
|
||||||
if (filldir(dirent,
|
if (!dir_emit(ctx,
|
||||||
rinfo->dir_dname[off - fi->offset],
|
rinfo->dir_dname[off - fi->offset],
|
||||||
rinfo->dir_dname_len[off - fi->offset],
|
rinfo->dir_dname_len[off - fi->offset],
|
||||||
pos,
|
ceph_translate_ino(inode->i_sb, ino), ftype)) {
|
||||||
ceph_translate_ino(inode->i_sb, ino), ftype) < 0) {
|
|
||||||
dout("filldir stopping us...\n");
|
dout("filldir stopping us...\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
off++;
|
off++;
|
||||||
filp->f_pos = pos + 1;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fi->last_name) {
|
if (fi->last_name) {
|
||||||
|
@ -417,7 +414,7 @@ more:
|
||||||
if (!ceph_frag_is_rightmost(frag)) {
|
if (!ceph_frag_is_rightmost(frag)) {
|
||||||
frag = ceph_frag_next(frag);
|
frag = ceph_frag_next(frag);
|
||||||
off = 0;
|
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);
|
dout("readdir next frag is %x\n", frag);
|
||||||
goto more;
|
goto more;
|
||||||
}
|
}
|
||||||
|
@ -432,11 +429,11 @@ more:
|
||||||
if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
|
if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
|
||||||
dout(" marking %p complete\n", inode);
|
dout(" marking %p complete\n", inode);
|
||||||
__ceph_dir_set_complete(ci, fi->dir_release_count);
|
__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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,7 +1265,7 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
|
||||||
|
|
||||||
const struct file_operations ceph_dir_fops = {
|
const struct file_operations ceph_dir_fops = {
|
||||||
.read = ceph_read_dir,
|
.read = ceph_read_dir,
|
||||||
.readdir = ceph_readdir,
|
.iterate = ceph_readdir,
|
||||||
.llseek = ceph_dir_llseek,
|
.llseek = ceph_dir_llseek,
|
||||||
.open = ceph_open,
|
.open = ceph_open,
|
||||||
.release = ceph_release,
|
.release = ceph_release,
|
||||||
|
|
|
@ -968,7 +968,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_dir_ops = {
|
const struct file_operations cifs_dir_ops = {
|
||||||
.readdir = cifs_readdir,
|
.iterate = cifs_readdir,
|
||||||
.release = cifs_closedir,
|
.release = cifs_closedir,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.unlocked_ioctl = cifs_ioctl,
|
.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 int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
|
||||||
extern const struct file_operations cifs_dir_ops;
|
extern const struct file_operations cifs_dir_ops;
|
||||||
extern int cifs_dir_open(struct inode *inode, struct file *file);
|
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 */
|
/* Functions related to dir entries */
|
||||||
extern const struct dentry_operations cifs_dentry_ops;
|
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).
|
* every entry (do not increment for . or .. entry).
|
||||||
*/
|
*/
|
||||||
static int
|
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)
|
struct file *file, char **current_entry, int *num_to_ret)
|
||||||
{
|
{
|
||||||
__u16 search_flags;
|
__u16 search_flags;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int pos_in_buf = 0;
|
int pos_in_buf = 0;
|
||||||
loff_t first_entry_in_buffer;
|
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 cifsFileInfo *cfile = file->private_data;
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||||
struct TCP_Server_Info *server = tcon->ses->server;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
|
static int cifs_filldir(char *find_entry, struct file *file,
|
||||||
void *dirent, char *scratch_buf, unsigned int max_len)
|
struct dir_context *ctx,
|
||||||
|
char *scratch_buf, unsigned int max_len)
|
||||||
{
|
{
|
||||||
struct cifsFileInfo *file_info = file->private_data;
|
struct cifsFileInfo *file_info = file->private_data;
|
||||||
struct super_block *sb = file->f_path.dentry->d_sb;
|
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);
|
cifs_prime_dcache(file->f_dentry, &name, &fattr);
|
||||||
|
|
||||||
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
||||||
rc = filldir(dirent, name.name, name.len, file->f_pos, ino,
|
return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
|
||||||
fattr.cf_dtype);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
int cifs_readdir(struct file *file, struct dir_context *ctx)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned int xid;
|
unsigned int xid;
|
||||||
|
@ -772,103 +771,86 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||||
goto rddir2_exit;
|
goto rddir2_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ((int) file->f_pos) {
|
if (!dir_emit_dots(file, ctx))
|
||||||
case 0:
|
goto rddir2_exit;
|
||||||
if (filldir(direntry, ".", 1, file->f_pos,
|
|
||||||
file_inode(file)->i_ino, DT_DIR) < 0) {
|
/* 1) If search is active,
|
||||||
cifs_dbg(VFS, "Filldir for current dir failed\n");
|
is in current search buffer?
|
||||||
rc = -ENOMEM;
|
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;
|
||||||
|
}
|
||||||
|
} /* 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, ¤t_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;
|
break;
|
||||||
}
|
}
|
||||||
file->f_pos++;
|
/*
|
||||||
case 1:
|
* if buggy server returns . and .. late do we want to
|
||||||
if (filldir(direntry, "..", 2, file->f_pos,
|
* check for that here?
|
||||||
parent_ino(file->f_path.dentry), DT_DIR) < 0) {
|
*/
|
||||||
cifs_dbg(VFS, "Filldir for parent dir failed\n");
|
rc = cifs_filldir(current_entry, file, ctx,
|
||||||
rc = -ENOMEM;
|
tmp_buf, max_len);
|
||||||
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);
|
|
||||||
} */
|
|
||||||
|
|
||||||
tcon = tlink_tcon(cifsFile->tlink);
|
|
||||||
rc = find_cifs_entry(xid, tcon, file, ¤t_entry,
|
|
||||||
&num_to_fill);
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(FYI, "fce error %d\n", rc);
|
if (rc > 0)
|
||||||
goto rddir2_exit;
|
rc = 0;
|
||||||
} else if (current_entry != NULL) {
|
|
||||||
cifs_dbg(FYI, "entry %lld found\n", file->f_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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
|
ctx->pos++;
|
||||||
if (current_entry == NULL) {
|
if (ctx->pos ==
|
||||||
/* evaluate whether this case is an error */
|
cifsFile->srch_inf.index_of_last_entry) {
|
||||||
cifs_dbg(VFS, "past SMB end, num to fill %d i %d\n",
|
cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
|
||||||
num_to_fill, i);
|
ctx->pos, tmp_buf);
|
||||||
break;
|
cifs_save_resume_key(current_entry, cifsFile);
|
||||||
}
|
break;
|
||||||
/*
|
} else
|
||||||
* if buggy server returns . and .. late do we want to
|
current_entry =
|
||||||
* check for that here?
|
nxt_dir_entry(current_entry, end_of_smb,
|
||||||
*/
|
cifsFile->srch_inf.info_level);
|
||||||
rc = cifs_filldir(current_entry, file, filldir,
|
}
|
||||||
direntry, tmp_buf, max_len);
|
kfree(tmp_buf);
|
||||||
if (rc == -EOVERFLOW) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
kfree(tmp_buf);
|
|
||||||
break;
|
|
||||||
} /* end switch */
|
|
||||||
|
|
||||||
rddir2_exit:
|
rddir2_exit:
|
||||||
free_xid(xid);
|
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);
|
struct inode *new_inode, struct dentry *new_dentry);
|
||||||
|
|
||||||
/* dir file-ops */
|
/* 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 */
|
/* dentry ops */
|
||||||
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
|
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
|
||||||
static int coda_dentry_delete(const struct dentry *);
|
static int coda_dentry_delete(const struct dentry *);
|
||||||
|
|
||||||
/* support routines */
|
/* support routines */
|
||||||
static int coda_venus_readdir(struct file *coda_file, void *buf,
|
static int coda_venus_readdir(struct file *, struct dir_context *);
|
||||||
filldir_t filldir);
|
|
||||||
|
|
||||||
/* same as fs/bad_inode.c */
|
/* same as fs/bad_inode.c */
|
||||||
static int coda_return_EIO(void)
|
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 = {
|
const struct file_operations coda_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = coda_readdir,
|
.iterate = coda_readdir,
|
||||||
.open = coda_open,
|
.open = coda_open,
|
||||||
.release = coda_release,
|
.release = coda_release,
|
||||||
.fsync = coda_fsync,
|
.fsync = coda_fsync,
|
||||||
|
@ -378,7 +377,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
|
|
||||||
|
|
||||||
/* file operations for directories */
|
/* 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 coda_file_info *cfi;
|
||||||
struct file *host_file;
|
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)
|
if (!host_file->f_op)
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
|
|
||||||
if (host_file->f_op->readdir)
|
if (host_file->f_op->iterate) {
|
||||||
{
|
|
||||||
/* 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. */
|
|
||||||
struct inode *host_inode = file_inode(host_file);
|
struct inode *host_inode = file_inode(host_file);
|
||||||
|
|
||||||
mutex_lock(&host_inode->i_mutex);
|
mutex_lock(&host_inode->i_mutex);
|
||||||
host_file->f_pos = coda_file->f_pos;
|
|
||||||
|
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
if (!IS_DEADDIR(host_inode)) {
|
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);
|
file_accessed(host_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
coda_file->f_pos = host_file->f_pos;
|
|
||||||
mutex_unlock(&host_inode->i_mutex);
|
mutex_unlock(&host_inode->i_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else /* Venus: we must read Venus dirents from a file */
|
/* Venus: we must read Venus dirents from a file */
|
||||||
ret = coda_venus_readdir(coda_file, buf, filldir);
|
return coda_venus_readdir(coda_file, ctx);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int CDT2DT(unsigned char cdt)
|
static inline unsigned int CDT2DT(unsigned char cdt)
|
||||||
|
@ -437,10 +425,8 @@ static inline unsigned int CDT2DT(unsigned char cdt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* support routines */
|
/* support routines */
|
||||||
static int coda_venus_readdir(struct file *coda_file, void *buf,
|
static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
|
||||||
filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
int result = 0; /* # of entries returned */
|
|
||||||
struct coda_file_info *cfi;
|
struct coda_file_info *cfi;
|
||||||
struct coda_inode_info *cii;
|
struct coda_inode_info *cii;
|
||||||
struct file *host_file;
|
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);
|
vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
|
||||||
if (!vdir) return -ENOMEM;
|
if (!vdir) return -ENOMEM;
|
||||||
|
|
||||||
if (coda_file->f_pos == 0) {
|
if (!dir_emit_dots(coda_file, ctx))
|
||||||
ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
|
goto out;
|
||||||
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++;
|
|
||||||
}
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* read entries from the directory file */
|
/* 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));
|
sizeof(*vdir));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
|
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 */
|
/* Make sure we skip '.' and '..', we already got those */
|
||||||
if (name.name[0] == '.' && (name.len == 1 ||
|
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;
|
vdir->d_fileno = name.len = 0;
|
||||||
|
|
||||||
/* skip null entries */
|
/* skip null entries */
|
||||||
|
@ -520,19 +495,16 @@ static int coda_venus_readdir(struct file *coda_file, void *buf,
|
||||||
if (!ino) ino = vdir->d_fileno;
|
if (!ino) ino = vdir->d_fileno;
|
||||||
|
|
||||||
type = CDT2DT(vdir->d_type);
|
type = CDT2DT(vdir->d_type);
|
||||||
ret = filldir(buf, name.name, name.len,
|
if (!dir_emit(ctx, name.name, name.len, ino, type))
|
||||||
coda_file->f_pos, ino, type);
|
break;
|
||||||
/* failure means no space for filling in this round */
|
|
||||||
if (ret < 0) break;
|
|
||||||
result++;
|
|
||||||
}
|
}
|
||||||
/* we'll always have progress because d_reclen is unsigned and
|
/* we'll always have progress because d_reclen is unsigned and
|
||||||
* we've already established it is non-zero. */
|
* we've already established it is non-zero. */
|
||||||
coda_file->f_pos += vdir->d_reclen;
|
ctx->pos += vdir->d_reclen;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
kfree(vdir);
|
kfree(vdir);
|
||||||
return result ? result : ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when a cache lookup succeeds */
|
/* called when a cache lookup succeeds */
|
||||||
|
|
43
fs/compat.c
43
fs/compat.c
|
@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct compat_readdir_callback {
|
struct compat_readdir_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
struct compat_old_linux_dirent __user *dirent;
|
struct compat_old_linux_dirent __user *dirent;
|
||||||
int result;
|
int result;
|
||||||
};
|
};
|
||||||
|
@ -873,15 +874,15 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
struct fd f = fdget(fd);
|
struct fd f = fdget(fd);
|
||||||
struct compat_readdir_callback buf;
|
struct compat_readdir_callback buf = {
|
||||||
|
.ctx.actor = compat_fillonedir,
|
||||||
|
.dirent = dirent
|
||||||
|
};
|
||||||
|
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
buf.result = 0;
|
error = iterate_dir(f.file, &buf.ctx);
|
||||||
buf.dirent = dirent;
|
|
||||||
|
|
||||||
error = vfs_readdir(f.file, compat_fillonedir, &buf);
|
|
||||||
if (buf.result)
|
if (buf.result)
|
||||||
error = buf.result;
|
error = buf.result;
|
||||||
|
|
||||||
|
@ -897,6 +898,7 @@ struct compat_linux_dirent {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct compat_getdents_callback {
|
struct compat_getdents_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
struct compat_linux_dirent __user *current_dir;
|
struct compat_linux_dirent __user *current_dir;
|
||||||
struct compat_linux_dirent __user *previous;
|
struct compat_linux_dirent __user *previous;
|
||||||
int count;
|
int count;
|
||||||
|
@ -951,7 +953,11 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
||||||
{
|
{
|
||||||
struct fd f;
|
struct fd f;
|
||||||
struct compat_linux_dirent __user * lastdirent;
|
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;
|
int error;
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||||
|
@ -961,17 +967,12 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
buf.current_dir = dirent;
|
error = iterate_dir(f.file, &buf.ctx);
|
||||||
buf.previous = NULL;
|
|
||||||
buf.count = count;
|
|
||||||
buf.error = 0;
|
|
||||||
|
|
||||||
error = vfs_readdir(f.file, compat_filldir, &buf);
|
|
||||||
if (error >= 0)
|
if (error >= 0)
|
||||||
error = buf.error;
|
error = buf.error;
|
||||||
lastdirent = buf.previous;
|
lastdirent = buf.previous;
|
||||||
if (lastdirent) {
|
if (lastdirent) {
|
||||||
if (put_user(f.file->f_pos, &lastdirent->d_off))
|
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
else
|
else
|
||||||
error = count - buf.count;
|
error = count - buf.count;
|
||||||
|
@ -983,6 +984,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
||||||
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
|
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
|
||||||
|
|
||||||
struct compat_getdents_callback64 {
|
struct compat_getdents_callback64 {
|
||||||
|
struct dir_context ctx;
|
||||||
struct linux_dirent64 __user *current_dir;
|
struct linux_dirent64 __user *current_dir;
|
||||||
struct linux_dirent64 __user *previous;
|
struct linux_dirent64 __user *previous;
|
||||||
int count;
|
int count;
|
||||||
|
@ -1036,7 +1038,11 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
|
||||||
{
|
{
|
||||||
struct fd f;
|
struct fd f;
|
||||||
struct linux_dirent64 __user * lastdirent;
|
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;
|
int error;
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||||
|
@ -1046,17 +1052,12 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
buf.current_dir = dirent;
|
error = iterate_dir(f.file, &buf.ctx);
|
||||||
buf.previous = NULL;
|
|
||||||
buf.count = count;
|
|
||||||
buf.error = 0;
|
|
||||||
|
|
||||||
error = vfs_readdir(f.file, compat_filldir64, &buf);
|
|
||||||
if (error >= 0)
|
if (error >= 0)
|
||||||
error = buf.error;
|
error = buf.error;
|
||||||
lastdirent = buf.previous;
|
lastdirent = buf.previous;
|
||||||
if (lastdirent) {
|
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))
|
if (__put_user_unaligned(d_off, &lastdirent->d_off))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
else
|
else
|
||||||
|
|
|
@ -66,7 +66,6 @@
|
||||||
#include <linux/gigaset_dev.h>
|
#include <linux/gigaset_dev.h>
|
||||||
|
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
#include <linux/loop.h>
|
|
||||||
#include <linux/cdrom.h>
|
#include <linux/cdrom.h>
|
||||||
#include <linux/fd.h>
|
#include <linux/fd.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
|
@ -954,8 +953,6 @@ COMPATIBLE_IOCTL(MTIOCTOP)
|
||||||
/* Socket level stuff */
|
/* Socket level stuff */
|
||||||
COMPATIBLE_IOCTL(FIOQSIZE)
|
COMPATIBLE_IOCTL(FIOQSIZE)
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
/* loop */
|
|
||||||
IGNORE_IOCTL(LOOP_CLR_FD)
|
|
||||||
/* md calls this on random blockdevs */
|
/* md calls this on random blockdevs */
|
||||||
IGNORE_IOCTL(RAID_VERSION)
|
IGNORE_IOCTL(RAID_VERSION)
|
||||||
/* qemu/qemu-img might call these two on plain files for probing */
|
/* 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;
|
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 super_block *sb = dentry->d_sb;
|
||||||
struct configfs_dirent * parent_sd = dentry->d_fsdata;
|
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;
|
struct list_head *p, *q = &cursor->s_sibling;
|
||||||
ino_t ino = 0;
|
ino_t ino = 0;
|
||||||
int i = filp->f_pos;
|
|
||||||
|
|
||||||
switch (i) {
|
if (!dir_emit_dots(file, ctx))
|
||||||
case 0:
|
return 0;
|
||||||
ino = dentry->d_inode->i_ino;
|
if (ctx->pos == 2) {
|
||||||
if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
|
spin_lock(&configfs_dirent_lock);
|
||||||
break;
|
list_move(q, &parent_sd->s_children);
|
||||||
filp->f_pos++;
|
spin_unlock(&configfs_dirent_lock);
|
||||||
i++;
|
}
|
||||||
/* fallthrough */
|
for (p = q->next; p != &parent_sd->s_children; p = p->next) {
|
||||||
case 1:
|
struct configfs_dirent *next;
|
||||||
ino = parent_ino(dentry);
|
const char *name;
|
||||||
if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
|
int len;
|
||||||
break;
|
struct inode *inode = NULL;
|
||||||
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;
|
|
||||||
|
|
||||||
next = list_entry(p, struct configfs_dirent,
|
next = list_entry(p, struct configfs_dirent, s_sibling);
|
||||||
s_sibling);
|
if (!next->s_element)
|
||||||
if (!next->s_element)
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
name = configfs_get_name(next);
|
name = configfs_get_name(next);
|
||||||
len = strlen(name);
|
len = strlen(name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We'll have a dentry and an inode for
|
* We'll have a dentry and an inode for
|
||||||
* PINNED items and for open attribute
|
* PINNED items and for open attribute
|
||||||
* files. We lock here to prevent a race
|
* files. We lock here to prevent a race
|
||||||
* with configfs_d_iput() clearing
|
* with configfs_d_iput() clearing
|
||||||
* s_dentry before calling iput().
|
* s_dentry before calling iput().
|
||||||
*
|
*
|
||||||
* Why do we go to the trouble? If
|
* Why do we go to the trouble? If
|
||||||
* someone has an attribute file open,
|
* someone has an attribute file open,
|
||||||
* the inode number should match until
|
* the inode number should match until
|
||||||
* they close it. Beyond that, we don't
|
* they close it. Beyond that, we don't
|
||||||
* care.
|
* care.
|
||||||
*/
|
*/
|
||||||
spin_lock(&configfs_dirent_lock);
|
spin_lock(&configfs_dirent_lock);
|
||||||
dentry = next->s_dentry;
|
dentry = next->s_dentry;
|
||||||
if (dentry)
|
if (dentry)
|
||||||
inode = dentry->d_inode;
|
inode = dentry->d_inode;
|
||||||
if (inode)
|
if (inode)
|
||||||
ino = inode->i_ino;
|
ino = inode->i_ino;
|
||||||
spin_unlock(&configfs_dirent_lock);
|
spin_unlock(&configfs_dirent_lock);
|
||||||
if (!inode)
|
if (!inode)
|
||||||
ino = iunique(sb, 2);
|
ino = iunique(sb, 2);
|
||||||
|
|
||||||
if (filldir(dirent, name, len, filp->f_pos, ino,
|
if (!dir_emit(ctx, name, len, ino, dt_type(next)))
|
||||||
dt_type(next)) < 0)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
spin_lock(&configfs_dirent_lock);
|
spin_lock(&configfs_dirent_lock);
|
||||||
list_move(q, p);
|
list_move(q, p);
|
||||||
spin_unlock(&configfs_dirent_lock);
|
spin_unlock(&configfs_dirent_lock);
|
||||||
p = q;
|
p = q;
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1643,7 @@ const struct file_operations configfs_dir_operations = {
|
||||||
.release = configfs_dir_close,
|
.release = configfs_dir_close,
|
||||||
.llseek = configfs_dir_lseek,
|
.llseek = configfs_dir_lseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = configfs_readdir,
|
.iterate = configfs_readdir,
|
||||||
};
|
};
|
||||||
|
|
||||||
int configfs_register_subsystem(struct configfs_subsystem *subsys)
|
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.
|
* 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;
|
struct super_block *sb = inode->i_sb;
|
||||||
char *buf;
|
char *buf;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int copied;
|
|
||||||
|
|
||||||
/* Offset within the thing. */
|
/* Offset within the thing. */
|
||||||
offset = filp->f_pos;
|
if (ctx->pos >= inode->i_size)
|
||||||
if (offset >= inode->i_size)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
offset = ctx->pos;
|
||||||
/* Directory entries are always 4-byte aligned */
|
/* Directory entries are always 4-byte aligned */
|
||||||
if (offset & 3)
|
if (offset & 3)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -369,14 +368,13 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
copied = 0;
|
|
||||||
while (offset < inode->i_size) {
|
while (offset < inode->i_size) {
|
||||||
struct cramfs_inode *de;
|
struct cramfs_inode *de;
|
||||||
unsigned long nextoffset;
|
unsigned long nextoffset;
|
||||||
char *name;
|
char *name;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
umode_t mode;
|
umode_t mode;
|
||||||
int namelen, error;
|
int namelen;
|
||||||
|
|
||||||
mutex_lock(&read_mutex);
|
mutex_lock(&read_mutex);
|
||||||
de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);
|
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;
|
break;
|
||||||
namelen--;
|
namelen--;
|
||||||
}
|
}
|
||||||
error = filldir(dirent, buf, namelen, offset, ino, mode >> 12);
|
if (!dir_emit(ctx, buf, namelen, ino, mode >> 12))
|
||||||
if (error)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
offset = nextoffset;
|
ctx->pos = offset = nextoffset;
|
||||||
filp->f_pos = offset;
|
|
||||||
copied++;
|
|
||||||
}
|
}
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -547,7 +542,7 @@ static const struct address_space_operations cramfs_aops = {
|
||||||
static const struct file_operations cramfs_directory_operations = {
|
static const struct file_operations cramfs_directory_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = cramfs_readdir,
|
.iterate = cramfs_readdir,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct inode_operations cramfs_dir_inode_operations = {
|
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 {
|
struct ecryptfs_getdents_callback {
|
||||||
void *dirent;
|
struct dir_context ctx;
|
||||||
|
struct dir_context *caller;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
filldir_t filldir;
|
|
||||||
int filldir_called;
|
int filldir_called;
|
||||||
int entries_written;
|
int entries_written;
|
||||||
};
|
};
|
||||||
|
@ -96,9 +96,10 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
|
||||||
rc);
|
rc);
|
||||||
goto out;
|
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);
|
kfree(name);
|
||||||
if (rc >= 0)
|
if (!rc)
|
||||||
buf->entries_written++;
|
buf->entries_written++;
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -107,27 +108,23 @@ out:
|
||||||
/**
|
/**
|
||||||
* ecryptfs_readdir
|
* ecryptfs_readdir
|
||||||
* @file: The eCryptfs directory file
|
* @file: The eCryptfs directory file
|
||||||
* @dirent: Directory entry handle
|
* @ctx: The actor to feed the entries to
|
||||||
* @filldir: The filldir callback function
|
|
||||||
*/
|
*/
|
||||||
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;
|
int rc;
|
||||||
struct file *lower_file;
|
struct file *lower_file;
|
||||||
struct inode *inode;
|
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 = ecryptfs_file_to_lower(file);
|
||||||
lower_file->f_pos = file->f_pos;
|
lower_file->f_pos = ctx->pos;
|
||||||
inode = file_inode(file);
|
inode = file_inode(file);
|
||||||
memset(&buf, 0, sizeof(buf));
|
rc = iterate_dir(lower_file, &buf.ctx);
|
||||||
buf.dirent = dirent;
|
ctx->pos = buf.ctx.pos;
|
||||||
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;
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (buf.filldir_called && !buf.entries_written)
|
if (buf.filldir_called && !buf.entries_written)
|
||||||
|
@ -344,7 +341,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const struct file_operations ecryptfs_dir_fops = {
|
const struct file_operations ecryptfs_dir_fops = {
|
||||||
.readdir = ecryptfs_readdir,
|
.iterate = ecryptfs_readdir,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
@ -365,7 +362,7 @@ const struct file_operations ecryptfs_main_fops = {
|
||||||
.aio_read = ecryptfs_read_update_atime,
|
.aio_read = ecryptfs_read_update_atime,
|
||||||
.write = do_sync_write,
|
.write = do_sync_write,
|
||||||
.aio_write = generic_file_aio_write,
|
.aio_write = generic_file_aio_write,
|
||||||
.readdir = ecryptfs_readdir,
|
.iterate = ecryptfs_readdir,
|
||||||
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = ecryptfs_compat_ioctl,
|
.compat_ioctl = ecryptfs_compat_ioctl,
|
||||||
|
|
75
fs/efs/dir.c
75
fs/efs/dir.c
|
@ -7,40 +7,38 @@
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include "efs.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 = {
|
const struct file_operations efs_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = efs_readdir,
|
.iterate = efs_readdir,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct inode_operations efs_dir_inode_operations = {
|
const struct inode_operations efs_dir_inode_operations = {
|
||||||
.lookup = efs_lookup,
|
.lookup = efs_lookup,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
|
static int efs_readdir(struct file *file, struct dir_context *ctx)
|
||||||
struct inode *inode = file_inode(filp);
|
{
|
||||||
struct buffer_head *bh;
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
struct efs_dir *dirblock;
|
|
||||||
struct efs_dentry *dirslot;
|
|
||||||
efs_ino_t inodenum;
|
|
||||||
efs_block_t block;
|
efs_block_t block;
|
||||||
int slot, namelen;
|
int slot;
|
||||||
char *nameptr;
|
|
||||||
|
|
||||||
if (inode->i_size & (EFS_DIRBSIZE-1))
|
if (inode->i_size & (EFS_DIRBSIZE-1))
|
||||||
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
|
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
|
||||||
|
|
||||||
/* work out where this entry can be found */
|
/* 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 */
|
/* each block contains at most 256 slots */
|
||||||
slot = filp->f_pos & 0xff;
|
slot = ctx->pos & 0xff;
|
||||||
|
|
||||||
/* look at all blocks */
|
/* look at all blocks */
|
||||||
while (block < inode->i_blocks) {
|
while (block < inode->i_blocks) {
|
||||||
|
struct efs_dir *dirblock;
|
||||||
|
struct buffer_head *bh;
|
||||||
|
|
||||||
/* read the dir block */
|
/* read the dir block */
|
||||||
bh = sb_bread(inode->i_sb, efs_bmap(inode, 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (slot < dirblock->slots) {
|
for (; slot < dirblock->slots; slot++) {
|
||||||
if (dirblock->space[slot] == 0) {
|
struct efs_dentry *dirslot;
|
||||||
slot++;
|
efs_ino_t inodenum;
|
||||||
|
const char *nameptr;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
if (dirblock->space[slot] == 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
|
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
|
#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);
|
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
|
#endif
|
||||||
if (namelen > 0) {
|
if (!namelen)
|
||||||
/* found the next entry */
|
continue;
|
||||||
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
/* found the next entry */
|
||||||
|
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
||||||
|
|
||||||
/* copy filename and data in dirslot */
|
/* sanity check */
|
||||||
filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN);
|
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
|
||||||
|
printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
|
||||||
/* sanity check */
|
continue;
|
||||||
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
|
}
|
||||||
printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
|
|
||||||
slot++;
|
/* copy filename and data in dirslot */
|
||||||
continue;
|
if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) {
|
||||||
}
|
brelse(bh);
|
||||||
|
return 0;
|
||||||
/* store position of next slot */
|
|
||||||
if (++slot == dirblock->slots) {
|
|
||||||
slot = 0;
|
|
||||||
block++;
|
|
||||||
}
|
|
||||||
brelse(bh);
|
|
||||||
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
slot++;
|
|
||||||
}
|
}
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
|
||||||
slot = 0;
|
slot = 0;
|
||||||
block++;
|
block++;
|
||||||
}
|
}
|
||||||
|
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
||||||
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
|
||||||
out:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,22 +239,19 @@ void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
loff_t pos = ctx->pos;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
unsigned int offset = pos & ~PAGE_CACHE_MASK;
|
unsigned int offset = pos & ~PAGE_CACHE_MASK;
|
||||||
unsigned long n = pos >> PAGE_CACHE_SHIFT;
|
unsigned long n = pos >> PAGE_CACHE_SHIFT;
|
||||||
unsigned long npages = dir_pages(inode);
|
unsigned long npages = dir_pages(inode);
|
||||||
unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
|
unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
|
||||||
unsigned char *types = NULL;
|
int need_revalidate = (file->f_version != inode->i_version);
|
||||||
int need_revalidate = (filp->f_version != inode->i_version);
|
|
||||||
|
|
||||||
if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
|
if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
types = exofs_filetype_table;
|
|
||||||
|
|
||||||
for ( ; n < npages; n++, offset = 0) {
|
for ( ; n < npages; n++, offset = 0) {
|
||||||
char *kaddr, *limit;
|
char *kaddr, *limit;
|
||||||
struct exofs_dir_entry *de;
|
struct exofs_dir_entry *de;
|
||||||
|
@ -263,7 +260,7 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
if (IS_ERR(page)) {
|
if (IS_ERR(page)) {
|
||||||
EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
|
EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
|
||||||
inode->i_ino);
|
inode->i_ino);
|
||||||
filp->f_pos += PAGE_CACHE_SIZE - offset;
|
ctx->pos += PAGE_CACHE_SIZE - offset;
|
||||||
return PTR_ERR(page);
|
return PTR_ERR(page);
|
||||||
}
|
}
|
||||||
kaddr = page_address(page);
|
kaddr = page_address(page);
|
||||||
|
@ -271,9 +268,9 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
if (offset) {
|
if (offset) {
|
||||||
offset = exofs_validate_entry(kaddr, offset,
|
offset = exofs_validate_entry(kaddr, offset,
|
||||||
chunk_mask);
|
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;
|
need_revalidate = 0;
|
||||||
}
|
}
|
||||||
de = (struct exofs_dir_entry *)(kaddr + offset);
|
de = (struct exofs_dir_entry *)(kaddr + offset);
|
||||||
|
@ -288,27 +285,24 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (de->inode_no) {
|
if (de->inode_no) {
|
||||||
int over;
|
unsigned char t;
|
||||||
unsigned char d_type = DT_UNKNOWN;
|
|
||||||
|
|
||||||
if (types && de->file_type < EXOFS_FT_MAX)
|
if (de->file_type < EXOFS_FT_MAX)
|
||||||
d_type = types[de->file_type];
|
t = exofs_filetype_table[de->file_type];
|
||||||
|
else
|
||||||
|
t = DT_UNKNOWN;
|
||||||
|
|
||||||
offset = (char *)de - kaddr;
|
if (!dir_emit(ctx, de->name, de->name_len,
|
||||||
over = filldir(dirent, de->name, de->name_len,
|
|
||||||
(n<<PAGE_CACHE_SHIFT) | offset,
|
|
||||||
le64_to_cpu(de->inode_no),
|
le64_to_cpu(de->inode_no),
|
||||||
d_type);
|
t)) {
|
||||||
if (over) {
|
|
||||||
exofs_put_page(page);
|
exofs_put_page(page);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filp->f_pos += le16_to_cpu(de->rec_len);
|
ctx->pos += le16_to_cpu(de->rec_len);
|
||||||
}
|
}
|
||||||
exofs_put_page(page);
|
exofs_put_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,5 +663,5 @@ not_empty:
|
||||||
const struct file_operations exofs_dir_operations = {
|
const struct file_operations exofs_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.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 getdents_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
char *name; /* name that was found. It already points to a
|
char *name; /* name that was found. It already points to a
|
||||||
buffer NAME_MAX+1 is size */
|
buffer NAME_MAX+1 is size */
|
||||||
unsigned long ino; /* the inum we are looking for */
|
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;
|
struct inode *dir = path->dentry->d_inode;
|
||||||
int error;
|
int error;
|
||||||
struct file *file;
|
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;
|
error = -ENOTDIR;
|
||||||
if (!dir || !S_ISDIR(dir->i_mode))
|
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;
|
goto out;
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (!file->f_op->readdir)
|
if (!file->f_op->iterate)
|
||||||
goto out_close;
|
goto out_close;
|
||||||
|
|
||||||
buffer.name = name;
|
|
||||||
buffer.ino = child->d_inode->i_ino;
|
|
||||||
buffer.found = 0;
|
|
||||||
buffer.sequence = 0;
|
buffer.sequence = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int old_seq = buffer.sequence;
|
int old_seq = buffer.sequence;
|
||||||
|
|
||||||
error = vfs_readdir(file, filldir_one, &buffer);
|
error = iterate_dir(file, &buffer.ctx);
|
||||||
if (buffer.found) {
|
if (buffer.found) {
|
||||||
error = 0;
|
error = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -287,17 +287,17 @@ static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
loff_t pos = ctx->pos;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
unsigned int offset = pos & ~PAGE_CACHE_MASK;
|
unsigned int offset = pos & ~PAGE_CACHE_MASK;
|
||||||
unsigned long n = pos >> PAGE_CACHE_SHIFT;
|
unsigned long n = pos >> PAGE_CACHE_SHIFT;
|
||||||
unsigned long npages = dir_pages(inode);
|
unsigned long npages = dir_pages(inode);
|
||||||
unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
|
unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
|
||||||
unsigned char *types = NULL;
|
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))
|
if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -314,16 +314,16 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
|
||||||
ext2_error(sb, __func__,
|
ext2_error(sb, __func__,
|
||||||
"bad page in #%lu",
|
"bad page in #%lu",
|
||||||
inode->i_ino);
|
inode->i_ino);
|
||||||
filp->f_pos += PAGE_CACHE_SIZE - offset;
|
ctx->pos += PAGE_CACHE_SIZE - offset;
|
||||||
return PTR_ERR(page);
|
return PTR_ERR(page);
|
||||||
}
|
}
|
||||||
kaddr = page_address(page);
|
kaddr = page_address(page);
|
||||||
if (unlikely(need_revalidate)) {
|
if (unlikely(need_revalidate)) {
|
||||||
if (offset) {
|
if (offset) {
|
||||||
offset = ext2_validate_entry(kaddr, offset, chunk_mask);
|
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;
|
need_revalidate = 0;
|
||||||
}
|
}
|
||||||
de = (ext2_dirent *)(kaddr+offset);
|
de = (ext2_dirent *)(kaddr+offset);
|
||||||
|
@ -336,22 +336,19 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (de->inode) {
|
if (de->inode) {
|
||||||
int over;
|
|
||||||
unsigned char d_type = DT_UNKNOWN;
|
unsigned char d_type = DT_UNKNOWN;
|
||||||
|
|
||||||
if (types && de->file_type < EXT2_FT_MAX)
|
if (types && de->file_type < EXT2_FT_MAX)
|
||||||
d_type = types[de->file_type];
|
d_type = types[de->file_type];
|
||||||
|
|
||||||
offset = (char *)de - kaddr;
|
if (!dir_emit(ctx, de->name, de->name_len,
|
||||||
over = filldir(dirent, de->name, de->name_len,
|
le32_to_cpu(de->inode),
|
||||||
(n<<PAGE_CACHE_SHIFT) | offset,
|
d_type)) {
|
||||||
le32_to_cpu(de->inode), d_type);
|
|
||||||
if (over) {
|
|
||||||
ext2_put_page(page);
|
ext2_put_page(page);
|
||||||
return 0;
|
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);
|
ext2_put_page(page);
|
||||||
}
|
}
|
||||||
|
@ -724,7 +721,7 @@ not_empty:
|
||||||
const struct file_operations ext2_dir_operations = {
|
const struct file_operations ext2_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = ext2_readdir,
|
.iterate = ext2_readdir,
|
||||||
.unlocked_ioctl = ext2_ioctl,
|
.unlocked_ioctl = ext2_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = ext2_compat_ioctl,
|
.compat_ioctl = ext2_compat_ioctl,
|
||||||
|
|
157
fs/ext3/dir.c
157
fs/ext3/dir.c
|
@ -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
|
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ext3_dx_readdir(struct file * filp,
|
static int ext3_dx_readdir(struct file *, struct dir_context *);
|
||||||
void * dirent, filldir_t filldir);
|
|
||||||
|
|
||||||
static unsigned char get_dtype(struct super_block *sb, int filetype)
|
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;
|
return error_msg == NULL ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext3_readdir(struct file * filp,
|
static int ext3_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void * dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int i, stored;
|
int i;
|
||||||
struct ext3_dir_entry_2 *de;
|
struct ext3_dir_entry_2 *de;
|
||||||
int err;
|
int err;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
int ret = 0;
|
|
||||||
int dir_has_error = 0;
|
int dir_has_error = 0;
|
||||||
|
|
||||||
if (is_dx_dir(inode)) {
|
if (is_dx_dir(inode)) {
|
||||||
err = ext3_dx_readdir(filp, dirent, filldir);
|
err = ext3_dx_readdir(file, ctx);
|
||||||
if (err != ERR_BAD_DX_DIR) {
|
if (err != ERR_BAD_DX_DIR)
|
||||||
ret = err;
|
return err;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* We don't set the inode dirty flag since it's not
|
* We don't set the inode dirty flag since it's not
|
||||||
* critical that it get flushed back to the disk.
|
* 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 = ctx->pos & (sb->s_blocksize - 1);
|
||||||
offset = filp->f_pos & (sb->s_blocksize - 1);
|
|
||||||
|
|
||||||
while (!error && !stored && filp->f_pos < inode->i_size) {
|
while (ctx->pos < inode->i_size) {
|
||||||
unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb);
|
unsigned long blk = ctx->pos >> EXT3_BLOCK_SIZE_BITS(sb);
|
||||||
struct buffer_head map_bh;
|
struct buffer_head map_bh;
|
||||||
struct buffer_head *bh = NULL;
|
struct buffer_head *bh = NULL;
|
||||||
|
|
||||||
|
@ -129,12 +122,12 @@ static int ext3_readdir(struct file * filp,
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
pgoff_t index = map_bh.b_blocknr >>
|
pgoff_t index = map_bh.b_blocknr >>
|
||||||
(PAGE_CACHE_SHIFT - inode->i_blkbits);
|
(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(
|
page_cache_sync_readahead(
|
||||||
sb->s_bdev->bd_inode->i_mapping,
|
sb->s_bdev->bd_inode->i_mapping,
|
||||||
&filp->f_ra, filp,
|
&file->f_ra, file,
|
||||||
index, 1);
|
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);
|
bh = ext3_bread(NULL, inode, blk, 0, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,22 +139,21 @@ static int ext3_readdir(struct file * filp,
|
||||||
if (!dir_has_error) {
|
if (!dir_has_error) {
|
||||||
ext3_error(sb, __func__, "directory #%lu "
|
ext3_error(sb, __func__, "directory #%lu "
|
||||||
"contains a hole at offset %lld",
|
"contains a hole at offset %lld",
|
||||||
inode->i_ino, filp->f_pos);
|
inode->i_ino, ctx->pos);
|
||||||
dir_has_error = 1;
|
dir_has_error = 1;
|
||||||
}
|
}
|
||||||
/* corrupt size? Maybe no more blocks to read */
|
/* corrupt size? Maybe no more blocks to read */
|
||||||
if (filp->f_pos > inode->i_blocks << 9)
|
if (ctx->pos > inode->i_blocks << 9)
|
||||||
break;
|
break;
|
||||||
filp->f_pos += sb->s_blocksize - offset;
|
ctx->pos += sb->s_blocksize - offset;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
revalidate:
|
|
||||||
/* If the dir block has changed since the last call to
|
/* If the dir block has changed since the last call to
|
||||||
* readdir(2), then we might be pointing to an invalid
|
* readdir(2), then we might be pointing to an invalid
|
||||||
* dirent right now. Scan from the start of the block
|
* dirent right now. Scan from the start of the block
|
||||||
* to make sure. */
|
* 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; ) {
|
for (i = 0; i < sb->s_blocksize && i < offset; ) {
|
||||||
de = (struct ext3_dir_entry_2 *)
|
de = (struct ext3_dir_entry_2 *)
|
||||||
(bh->b_data + i);
|
(bh->b_data + i);
|
||||||
|
@ -177,53 +169,40 @@ revalidate:
|
||||||
i += ext3_rec_len_from_disk(de->rec_len);
|
i += ext3_rec_len_from_disk(de->rec_len);
|
||||||
}
|
}
|
||||||
offset = i;
|
offset = i;
|
||||||
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
|
ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
|
||||||
| offset;
|
| 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) {
|
&& offset < sb->s_blocksize) {
|
||||||
de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
|
de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
|
||||||
if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
|
if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
|
||||||
bh, offset)) {
|
bh, offset)) {
|
||||||
/* On error, skip the f_pos to the
|
/* On error, skip the to the
|
||||||
next block. */
|
next block. */
|
||||||
filp->f_pos = (filp->f_pos |
|
ctx->pos = (ctx->pos |
|
||||||
(sb->s_blocksize - 1)) + 1;
|
(sb->s_blocksize - 1)) + 1;
|
||||||
brelse (bh);
|
break;
|
||||||
ret = stored;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
offset += ext3_rec_len_from_disk(de->rec_len);
|
offset += ext3_rec_len_from_disk(de->rec_len);
|
||||||
if (le32_to_cpu(de->inode)) {
|
if (le32_to_cpu(de->inode)) {
|
||||||
/* We might block in the next section
|
if (!dir_emit(ctx, de->name, de->name_len,
|
||||||
* if the data destination is
|
le32_to_cpu(de->inode),
|
||||||
* currently swapped out. So, use a
|
get_dtype(sb, de->file_type))) {
|
||||||
* version stamp to detect whether or
|
brelse(bh);
|
||||||
* not the directory has been modified
|
return 0;
|
||||||
* 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 += ext3_rec_len_from_disk(de->rec_len);
|
ctx->pos += ext3_rec_len_from_disk(de->rec_len);
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
brelse (bh);
|
brelse (bh);
|
||||||
|
if (ctx->pos < inode->i_size)
|
||||||
|
if (!dir_relax(inode))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
out:
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_32bit_api(void)
|
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
|
* 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.)
|
* one entry on the linked list, unless there are 62 bit hash collisions.)
|
||||||
*/
|
*/
|
||||||
static int call_filldir(struct file * filp, void * dirent,
|
static bool call_filldir(struct file *file, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct fname *fname)
|
struct fname *fname)
|
||||||
{
|
{
|
||||||
struct dir_private_info *info = filp->private_data;
|
struct dir_private_info *info = file->private_data;
|
||||||
loff_t curr_pos;
|
struct inode *inode = file_inode(file);
|
||||||
struct inode *inode = file_inode(filp);
|
struct super_block *sb = inode->i_sb;
|
||||||
struct super_block * sb;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
sb = inode->i_sb;
|
|
||||||
|
|
||||||
if (!fname) {
|
if (!fname) {
|
||||||
printk("call_filldir: called with null fname?!?\n");
|
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) {
|
while (fname) {
|
||||||
error = filldir(dirent, fname->name,
|
if (!dir_emit(ctx, fname->name, fname->name_len,
|
||||||
fname->name_len, curr_pos,
|
|
||||||
fname->inode,
|
fname->inode,
|
||||||
get_dtype(sb, fname->file_type));
|
get_dtype(sb, fname->file_type))) {
|
||||||
if (error) {
|
|
||||||
filp->f_pos = curr_pos;
|
|
||||||
info->extra_fname = fname;
|
info->extra_fname = fname;
|
||||||
return error;
|
return false;
|
||||||
}
|
}
|
||||||
fname = fname->next;
|
fname = fname->next;
|
||||||
}
|
}
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext3_dx_readdir(struct file * filp,
|
static int ext3_dx_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void * dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
struct dir_private_info *info = filp->private_data;
|
struct dir_private_info *info = file->private_data;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct fname *fname;
|
struct fname *fname;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
info = ext3_htree_create_dir_info(filp, filp->f_pos);
|
info = ext3_htree_create_dir_info(file, ctx->pos);
|
||||||
if (!info)
|
if (!info)
|
||||||
return -ENOMEM;
|
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 */
|
return 0; /* EOF */
|
||||||
|
|
||||||
/* Some one has messed with f_pos; reset the world */
|
/* 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);
|
free_rb_tree_fname(&info->root);
|
||||||
info->curr_node = NULL;
|
info->curr_node = NULL;
|
||||||
info->extra_fname = NULL;
|
info->extra_fname = NULL;
|
||||||
info->curr_hash = pos2maj_hash(filp, filp->f_pos);
|
info->curr_hash = pos2maj_hash(file, ctx->pos);
|
||||||
info->curr_minor_hash = pos2min_hash(filp, filp->f_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.
|
* chain, return them first.
|
||||||
*/
|
*/
|
||||||
if (info->extra_fname) {
|
if (info->extra_fname) {
|
||||||
if (call_filldir(filp, dirent, filldir, info->extra_fname))
|
if (!call_filldir(file, ctx, info->extra_fname))
|
||||||
goto finished;
|
goto finished;
|
||||||
info->extra_fname = NULL;
|
info->extra_fname = NULL;
|
||||||
goto next_node;
|
goto next_node;
|
||||||
|
@ -529,17 +500,17 @@ static int ext3_dx_readdir(struct file * filp,
|
||||||
* cached entries.
|
* cached entries.
|
||||||
*/
|
*/
|
||||||
if ((!info->curr_node) ||
|
if ((!info->curr_node) ||
|
||||||
(filp->f_version != inode->i_version)) {
|
(file->f_version != inode->i_version)) {
|
||||||
info->curr_node = NULL;
|
info->curr_node = NULL;
|
||||||
free_rb_tree_fname(&info->root);
|
free_rb_tree_fname(&info->root);
|
||||||
filp->f_version = inode->i_version;
|
file->f_version = inode->i_version;
|
||||||
ret = ext3_htree_fill_tree(filp, info->curr_hash,
|
ret = ext3_htree_fill_tree(file, info->curr_hash,
|
||||||
info->curr_minor_hash,
|
info->curr_minor_hash,
|
||||||
&info->next_hash);
|
&info->next_hash);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
filp->f_pos = ext3_get_htree_eof(filp);
|
ctx->pos = ext3_get_htree_eof(file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info->curr_node = rb_first(&info->root);
|
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);
|
fname = rb_entry(info->curr_node, struct fname, rb_hash);
|
||||||
info->curr_hash = fname->hash;
|
info->curr_hash = fname->hash;
|
||||||
info->curr_minor_hash = fname->minor_hash;
|
info->curr_minor_hash = fname->minor_hash;
|
||||||
if (call_filldir(filp, dirent, filldir, fname))
|
if (!call_filldir(file, ctx, fname))
|
||||||
break;
|
break;
|
||||||
next_node:
|
next_node:
|
||||||
info->curr_node = rb_next(info->curr_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;
|
info->curr_minor_hash = fname->minor_hash;
|
||||||
} else {
|
} else {
|
||||||
if (info->next_hash == ~0) {
|
if (info->next_hash == ~0) {
|
||||||
filp->f_pos = ext3_get_htree_eof(filp);
|
ctx->pos = ext3_get_htree_eof(file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info->curr_hash = info->next_hash;
|
info->curr_hash = info->next_hash;
|
||||||
|
@ -567,7 +538,7 @@ static int ext3_dx_readdir(struct file * filp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finished:
|
finished:
|
||||||
info->last_pos = filp->f_pos;
|
info->last_pos = ctx->pos;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,7 +553,7 @@ static int ext3_release_dir (struct inode * inode, struct file * filp)
|
||||||
const struct file_operations ext3_dir_operations = {
|
const struct file_operations ext3_dir_operations = {
|
||||||
.llseek = ext3_dir_llseek,
|
.llseek = ext3_dir_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = ext3_readdir,
|
.iterate = ext3_readdir,
|
||||||
.unlocked_ioctl = ext3_ioctl,
|
.unlocked_ioctl = ext3_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = ext3_compat_ioctl,
|
.compat_ioctl = ext3_compat_ioctl,
|
||||||
|
|
158
fs/ext4/dir.c
158
fs/ext4/dir.c
|
@ -29,8 +29,7 @@
|
||||||
#include "ext4.h"
|
#include "ext4.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
|
||||||
static int ext4_dx_readdir(struct file *filp,
|
static int ext4_dx_readdir(struct file *, struct dir_context *);
|
||||||
void *dirent, filldir_t filldir);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given dir-inode refers to an htree-indexed directory
|
* 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_readdir(struct file *filp,
|
static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void *dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int i, stored;
|
int i, stored;
|
||||||
struct ext4_dir_entry_2 *de;
|
struct ext4_dir_entry_2 *de;
|
||||||
int err;
|
int err;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
int ret = 0;
|
|
||||||
int dir_has_error = 0;
|
int dir_has_error = 0;
|
||||||
|
|
||||||
if (is_dx_dir(inode)) {
|
if (is_dx_dir(inode)) {
|
||||||
err = ext4_dx_readdir(filp, dirent, filldir);
|
err = ext4_dx_readdir(file, ctx);
|
||||||
if (err != ERR_BAD_DX_DIR) {
|
if (err != ERR_BAD_DX_DIR) {
|
||||||
ret = err;
|
return err;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* We don't set the inode dirty flag since it's not
|
* We don't set the inode dirty flag since it's not
|
||||||
* critical that it get flushed back to the disk.
|
* 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);
|
EXT4_INODE_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext4_has_inline_data(inode)) {
|
if (ext4_has_inline_data(inode)) {
|
||||||
int has_inline_data = 1;
|
int has_inline_data = 1;
|
||||||
ret = ext4_read_inline_dir(filp, dirent, filldir,
|
int ret = ext4_read_inline_dir(file, ctx,
|
||||||
&has_inline_data);
|
&has_inline_data);
|
||||||
if (has_inline_data)
|
if (has_inline_data)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
stored = 0;
|
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 ext4_map_blocks map;
|
||||||
struct buffer_head *bh = NULL;
|
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;
|
map.m_len = 1;
|
||||||
err = ext4_map_blocks(NULL, inode, &map, 0);
|
err = ext4_map_blocks(NULL, inode, &map, 0);
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
pgoff_t index = map.m_pblk >>
|
pgoff_t index = map.m_pblk >>
|
||||||
(PAGE_CACHE_SHIFT - inode->i_blkbits);
|
(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(
|
page_cache_sync_readahead(
|
||||||
sb->s_bdev->bd_inode->i_mapping,
|
sb->s_bdev->bd_inode->i_mapping,
|
||||||
&filp->f_ra, filp,
|
&file->f_ra, file,
|
||||||
index, 1);
|
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);
|
bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,16 +161,16 @@ static int ext4_readdir(struct file *filp,
|
||||||
*/
|
*/
|
||||||
if (!bh) {
|
if (!bh) {
|
||||||
if (!dir_has_error) {
|
if (!dir_has_error) {
|
||||||
EXT4_ERROR_FILE(filp, 0,
|
EXT4_ERROR_FILE(file, 0,
|
||||||
"directory contains a "
|
"directory contains a "
|
||||||
"hole at offset %llu",
|
"hole at offset %llu",
|
||||||
(unsigned long long) filp->f_pos);
|
(unsigned long long) ctx->pos);
|
||||||
dir_has_error = 1;
|
dir_has_error = 1;
|
||||||
}
|
}
|
||||||
/* corrupt size? Maybe no more blocks to read */
|
/* corrupt size? Maybe no more blocks to read */
|
||||||
if (filp->f_pos > inode->i_blocks << 9)
|
if (ctx->pos > inode->i_blocks << 9)
|
||||||
break;
|
break;
|
||||||
filp->f_pos += sb->s_blocksize - offset;
|
ctx->pos += sb->s_blocksize - offset;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,21 +178,20 @@ static int ext4_readdir(struct file *filp,
|
||||||
if (!buffer_verified(bh) &&
|
if (!buffer_verified(bh) &&
|
||||||
!ext4_dirent_csum_verify(inode,
|
!ext4_dirent_csum_verify(inode,
|
||||||
(struct ext4_dir_entry *)bh->b_data)) {
|
(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",
|
"at offset %llu",
|
||||||
(unsigned long long)filp->f_pos);
|
(unsigned long long)ctx->pos);
|
||||||
filp->f_pos += sb->s_blocksize - offset;
|
ctx->pos += sb->s_blocksize - offset;
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
set_buffer_verified(bh);
|
set_buffer_verified(bh);
|
||||||
|
|
||||||
revalidate:
|
|
||||||
/* If the dir block has changed since the last call to
|
/* If the dir block has changed since the last call to
|
||||||
* readdir(2), then we might be pointing to an invalid
|
* readdir(2), then we might be pointing to an invalid
|
||||||
* dirent right now. Scan from the start of the block
|
* dirent right now. Scan from the start of the block
|
||||||
* to make sure. */
|
* 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; ) {
|
for (i = 0; i < sb->s_blocksize && i < offset; ) {
|
||||||
de = (struct ext4_dir_entry_2 *)
|
de = (struct ext4_dir_entry_2 *)
|
||||||
(bh->b_data + i);
|
(bh->b_data + i);
|
||||||
|
@ -214,57 +208,46 @@ revalidate:
|
||||||
sb->s_blocksize);
|
sb->s_blocksize);
|
||||||
}
|
}
|
||||||
offset = i;
|
offset = i;
|
||||||
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
|
ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
|
||||||
| offset;
|
| 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) {
|
&& offset < sb->s_blocksize) {
|
||||||
de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
|
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,
|
bh->b_data, bh->b_size,
|
||||||
offset)) {
|
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;
|
(sb->s_blocksize - 1)) + 1;
|
||||||
brelse(bh);
|
break;
|
||||||
ret = stored;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
offset += ext4_rec_len_from_disk(de->rec_len,
|
offset += ext4_rec_len_from_disk(de->rec_len,
|
||||||
sb->s_blocksize);
|
sb->s_blocksize);
|
||||||
if (le32_to_cpu(de->inode)) {
|
if (le32_to_cpu(de->inode)) {
|
||||||
/* We might block in the next section
|
if (!dir_emit(ctx, de->name,
|
||||||
* 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,
|
de->name_len,
|
||||||
filp->f_pos,
|
|
||||||
le32_to_cpu(de->inode),
|
le32_to_cpu(de->inode),
|
||||||
get_dtype(sb, de->file_type));
|
get_dtype(sb, de->file_type))) {
|
||||||
if (error)
|
brelse(bh);
|
||||||
break;
|
return 0;
|
||||||
if (version != filp->f_version)
|
}
|
||||||
goto revalidate;
|
|
||||||
stored++;
|
|
||||||
}
|
}
|
||||||
filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
|
ctx->pos += ext4_rec_len_from_disk(de->rec_len,
|
||||||
sb->s_blocksize);
|
sb->s_blocksize);
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
if (ctx->pos < inode->i_size) {
|
||||||
|
if (!dir_relax(inode))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_32bit_api(void)
|
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
|
* 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.)
|
* one entry on the linked list, unless there are 62 bit hash collisions.)
|
||||||
*/
|
*/
|
||||||
static int call_filldir(struct file *filp, void *dirent,
|
static int call_filldir(struct file *file, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct fname *fname)
|
struct fname *fname)
|
||||||
{
|
{
|
||||||
struct dir_private_info *info = filp->private_data;
|
struct dir_private_info *info = file->private_data;
|
||||||
loff_t curr_pos;
|
struct inode *inode = file_inode(file);
|
||||||
struct inode *inode = file_inode(filp);
|
struct super_block *sb = inode->i_sb;
|
||||||
struct super_block *sb;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
sb = inode->i_sb;
|
|
||||||
|
|
||||||
if (!fname) {
|
if (!fname) {
|
||||||
ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
|
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);
|
inode->i_ino, current->comm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
|
ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
|
||||||
while (fname) {
|
while (fname) {
|
||||||
error = filldir(dirent, fname->name,
|
if (!dir_emit(ctx, fname->name,
|
||||||
fname->name_len, curr_pos,
|
fname->name_len,
|
||||||
fname->inode,
|
fname->inode,
|
||||||
get_dtype(sb, fname->file_type));
|
get_dtype(sb, fname->file_type))) {
|
||||||
if (error) {
|
|
||||||
filp->f_pos = curr_pos;
|
|
||||||
info->extra_fname = fname;
|
info->extra_fname = fname;
|
||||||
return error;
|
return 1;
|
||||||
}
|
}
|
||||||
fname = fname->next;
|
fname = fname->next;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_dx_readdir(struct file *filp,
|
static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void *dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
struct dir_private_info *info = filp->private_data;
|
struct dir_private_info *info = file->private_data;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
struct fname *fname;
|
struct fname *fname;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
info = ext4_htree_create_dir_info(filp, filp->f_pos);
|
info = ext4_htree_create_dir_info(file, ctx->pos);
|
||||||
if (!info)
|
if (!info)
|
||||||
return -ENOMEM;
|
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 */
|
return 0; /* EOF */
|
||||||
|
|
||||||
/* Some one has messed with f_pos; reset the world */
|
/* 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);
|
free_rb_tree_fname(&info->root);
|
||||||
info->curr_node = NULL;
|
info->curr_node = NULL;
|
||||||
info->extra_fname = NULL;
|
info->extra_fname = NULL;
|
||||||
info->curr_hash = pos2maj_hash(filp, filp->f_pos);
|
info->curr_hash = pos2maj_hash(file, ctx->pos);
|
||||||
info->curr_minor_hash = pos2min_hash(filp, filp->f_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.
|
* chain, return them first.
|
||||||
*/
|
*/
|
||||||
if (info->extra_fname) {
|
if (info->extra_fname) {
|
||||||
if (call_filldir(filp, dirent, filldir, info->extra_fname))
|
if (call_filldir(file, ctx, info->extra_fname))
|
||||||
goto finished;
|
goto finished;
|
||||||
info->extra_fname = NULL;
|
info->extra_fname = NULL;
|
||||||
goto next_node;
|
goto next_node;
|
||||||
|
@ -571,17 +547,17 @@ static int ext4_dx_readdir(struct file *filp,
|
||||||
* cached entries.
|
* cached entries.
|
||||||
*/
|
*/
|
||||||
if ((!info->curr_node) ||
|
if ((!info->curr_node) ||
|
||||||
(filp->f_version != inode->i_version)) {
|
(file->f_version != inode->i_version)) {
|
||||||
info->curr_node = NULL;
|
info->curr_node = NULL;
|
||||||
free_rb_tree_fname(&info->root);
|
free_rb_tree_fname(&info->root);
|
||||||
filp->f_version = inode->i_version;
|
file->f_version = inode->i_version;
|
||||||
ret = ext4_htree_fill_tree(filp, info->curr_hash,
|
ret = ext4_htree_fill_tree(file, info->curr_hash,
|
||||||
info->curr_minor_hash,
|
info->curr_minor_hash,
|
||||||
&info->next_hash);
|
&info->next_hash);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
filp->f_pos = ext4_get_htree_eof(filp);
|
ctx->pos = ext4_get_htree_eof(file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info->curr_node = rb_first(&info->root);
|
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);
|
fname = rb_entry(info->curr_node, struct fname, rb_hash);
|
||||||
info->curr_hash = fname->hash;
|
info->curr_hash = fname->hash;
|
||||||
info->curr_minor_hash = fname->minor_hash;
|
info->curr_minor_hash = fname->minor_hash;
|
||||||
if (call_filldir(filp, dirent, filldir, fname))
|
if (call_filldir(file, ctx, fname))
|
||||||
break;
|
break;
|
||||||
next_node:
|
next_node:
|
||||||
info->curr_node = rb_next(info->curr_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;
|
info->curr_minor_hash = fname->minor_hash;
|
||||||
} else {
|
} else {
|
||||||
if (info->next_hash == ~0) {
|
if (info->next_hash == ~0) {
|
||||||
filp->f_pos = ext4_get_htree_eof(filp);
|
ctx->pos = ext4_get_htree_eof(file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info->curr_hash = info->next_hash;
|
info->curr_hash = info->next_hash;
|
||||||
|
@ -609,7 +585,7 @@ static int ext4_dx_readdir(struct file *filp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finished:
|
finished:
|
||||||
info->last_pos = filp->f_pos;
|
info->last_pos = ctx->pos;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +600,7 @@ static int ext4_release_dir(struct inode *inode, struct file *filp)
|
||||||
const struct file_operations ext4_dir_operations = {
|
const struct file_operations ext4_dir_operations = {
|
||||||
.llseek = ext4_dir_llseek,
|
.llseek = ext4_dir_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = ext4_readdir,
|
.iterate = ext4_readdir,
|
||||||
.unlocked_ioctl = ext4_ioctl,
|
.unlocked_ioctl = ext4_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = ext4_compat_ioctl,
|
.compat_ioctl = ext4_compat_ioctl,
|
||||||
|
|
|
@ -2515,7 +2515,7 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
|
||||||
struct inode *parent,
|
struct inode *parent,
|
||||||
struct inode *inode);
|
struct inode *inode);
|
||||||
extern int ext4_read_inline_dir(struct file *filp,
|
extern int ext4_read_inline_dir(struct file *filp,
|
||||||
void *dirent, filldir_t filldir,
|
struct dir_context *ctx,
|
||||||
int *has_inline_data);
|
int *has_inline_data);
|
||||||
extern int htree_inlinedir_to_tree(struct file *dir_file,
|
extern int htree_inlinedir_to_tree(struct file *dir_file,
|
||||||
struct inode *dir, ext4_lblk_t block,
|
struct inode *dir, ext4_lblk_t block,
|
||||||
|
|
170
fs/ext4/inline.c
170
fs/ext4/inline.c
|
@ -1404,16 +1404,15 @@ out:
|
||||||
* offset as if '.' and '..' really take place.
|
* offset as if '.' and '..' really take place.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int ext4_read_inline_dir(struct file *filp,
|
int ext4_read_inline_dir(struct file *file,
|
||||||
void *dirent, filldir_t filldir,
|
struct dir_context *ctx,
|
||||||
int *has_inline_data)
|
int *has_inline_data)
|
||||||
{
|
{
|
||||||
int error = 0;
|
|
||||||
unsigned int offset, parent_ino;
|
unsigned int offset, parent_ino;
|
||||||
int i, stored;
|
int i;
|
||||||
struct ext4_dir_entry_2 *de;
|
struct ext4_dir_entry_2 *de;
|
||||||
struct super_block *sb;
|
struct super_block *sb;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
int ret, inline_size = 0;
|
int ret, inline_size = 0;
|
||||||
struct ext4_iloc iloc;
|
struct ext4_iloc iloc;
|
||||||
void *dir_buf = NULL;
|
void *dir_buf = NULL;
|
||||||
|
@ -1444,9 +1443,8 @@ int ext4_read_inline_dir(struct file *filp,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
sb = inode->i_sb;
|
sb = inode->i_sb;
|
||||||
stored = 0;
|
|
||||||
parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
|
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
|
* 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_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
|
||||||
extra_size = extra_offset + inline_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
|
||||||
* If the version has changed since the last call to
|
* dirent right now. Scan from the start of the inline
|
||||||
* readdir(2), then we might be pointing to an invalid
|
* dir to make sure.
|
||||||
* 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;) {
|
||||||
if (filp->f_version != inode->i_version) {
|
/*
|
||||||
for (i = 0; i < extra_size && i < offset;) {
|
* "." is with offset 0 and
|
||||||
/*
|
* ".." is dotdot_offset.
|
||||||
* "." is with offset 0 and
|
*/
|
||||||
* ".." is dotdot_offset.
|
if (!i) {
|
||||||
*/
|
i = dotdot_offset;
|
||||||
if (!i) {
|
continue;
|
||||||
i = dotdot_offset;
|
} else if (i == dotdot_offset) {
|
||||||
continue;
|
i = dotdot_size;
|
||||||
} 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;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* for other entry, the real offset in
|
||||||
if (filp->f_pos == dotdot_offset) {
|
* the buf has to be tuned accordingly.
|
||||||
error = filldir(dirent, "..", 2,
|
*/
|
||||||
dotdot_offset,
|
|
||||||
parent_ino, DT_DIR);
|
|
||||||
if (error)
|
|
||||||
break;
|
|
||||||
stored++;
|
|
||||||
|
|
||||||
filp->f_pos = dotdot_size;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
de = (struct ext4_dir_entry_2 *)
|
de = (struct ext4_dir_entry_2 *)
|
||||||
(dir_buf + filp->f_pos - extra_offset);
|
(dir_buf + i - extra_offset);
|
||||||
if (ext4_check_dir_entry(inode, filp, de,
|
/* It's too expensive to do a full
|
||||||
iloc.bh, dir_buf,
|
* dirent test each time round this
|
||||||
extra_size, filp->f_pos)) {
|
* loop, but we do have to test at
|
||||||
ret = stored;
|
* least that it is non-zero. A
|
||||||
goto out;
|
* failure will be detected in the
|
||||||
}
|
* dirent test below. */
|
||||||
if (le32_to_cpu(de->inode)) {
|
if (ext4_rec_len_from_disk(de->rec_len, extra_size)
|
||||||
/* We might block in the next section
|
< EXT4_DIR_REC_LEN(1))
|
||||||
* if the data destination is
|
break;
|
||||||
* currently swapped out. So, use a
|
i += ext4_rec_len_from_disk(de->rec_len,
|
||||||
* version stamp to detect whether or
|
extra_size);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
offset = i;
|
||||||
|
ctx->pos = offset;
|
||||||
|
file->f_version = inode->i_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + 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;
|
||||||
|
}
|
||||||
|
ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
kfree(dir_buf);
|
kfree(dir_buf);
|
||||||
|
|
|
@ -591,24 +591,19 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||||
return true;
|
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);
|
struct inode *inode = file_inode(file);
|
||||||
unsigned long npages = dir_blocks(inode);
|
unsigned long npages = dir_blocks(inode);
|
||||||
unsigned char *types = NULL;
|
|
||||||
unsigned int bit_pos = 0, start_bit_pos = 0;
|
unsigned int bit_pos = 0, start_bit_pos = 0;
|
||||||
int over = 0;
|
|
||||||
struct f2fs_dentry_block *dentry_blk = NULL;
|
struct f2fs_dentry_block *dentry_blk = NULL;
|
||||||
struct f2fs_dir_entry *de = NULL;
|
struct f2fs_dir_entry *de = NULL;
|
||||||
struct page *dentry_page = 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;
|
unsigned char d_type = DT_UNKNOWN;
|
||||||
int slots;
|
int slots;
|
||||||
|
|
||||||
types = f2fs_filetype_table;
|
bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
|
||||||
bit_pos = (pos % NR_DENTRY_IN_BLOCK);
|
|
||||||
n = (pos / NR_DENTRY_IN_BLOCK);
|
|
||||||
|
|
||||||
for ( ; n < npages; n++) {
|
for ( ; n < npages; n++) {
|
||||||
dentry_page = get_lock_data_page(inode, 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;
|
start_bit_pos = bit_pos;
|
||||||
dentry_blk = kmap(dentry_page);
|
dentry_blk = kmap(dentry_page);
|
||||||
while (bit_pos < NR_DENTRY_IN_BLOCK) {
|
while (bit_pos < NR_DENTRY_IN_BLOCK) {
|
||||||
d_type = DT_UNKNOWN;
|
|
||||||
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
|
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
|
||||||
NR_DENTRY_IN_BLOCK,
|
NR_DENTRY_IN_BLOCK,
|
||||||
bit_pos);
|
bit_pos);
|
||||||
if (bit_pos >= NR_DENTRY_IN_BLOCK)
|
if (bit_pos >= NR_DENTRY_IN_BLOCK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
ctx->pos += bit_pos - start_bit_pos;
|
||||||
de = &dentry_blk->dentry[bit_pos];
|
de = &dentry_blk->dentry[bit_pos];
|
||||||
if (types && de->file_type < F2FS_FT_MAX)
|
if (de->file_type < F2FS_FT_MAX)
|
||||||
d_type = types[de->file_type];
|
d_type = f2fs_filetype_table[de->file_type];
|
||||||
|
else
|
||||||
over = filldir(dirent,
|
d_type = DT_UNKNOWN;
|
||||||
dentry_blk->filename[bit_pos],
|
if (!dir_emit(ctx,
|
||||||
le16_to_cpu(de->name_len),
|
dentry_blk->filename[bit_pos],
|
||||||
(n * NR_DENTRY_IN_BLOCK) + bit_pos,
|
le16_to_cpu(de->name_len),
|
||||||
le32_to_cpu(de->ino), d_type);
|
le32_to_cpu(de->ino), d_type))
|
||||||
if (over) {
|
|
||||||
file->f_pos += bit_pos - start_bit_pos;
|
|
||||||
goto success;
|
goto success;
|
||||||
}
|
|
||||||
slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
|
slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
|
||||||
bit_pos += slots;
|
bit_pos += slots;
|
||||||
}
|
}
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK;
|
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
|
||||||
kunmap(dentry_page);
|
kunmap(dentry_page);
|
||||||
f2fs_put_page(dentry_page, 1);
|
f2fs_put_page(dentry_page, 1);
|
||||||
dentry_page = NULL;
|
dentry_page = NULL;
|
||||||
|
@ -659,7 +651,7 @@ success:
|
||||||
const struct file_operations f2fs_dir_operations = {
|
const struct file_operations f2fs_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = f2fs_readdir,
|
.iterate = f2fs_readdir,
|
||||||
.fsync = f2fs_sync_file,
|
.fsync = f2fs_sync_file,
|
||||||
.unlocked_ioctl = f2fs_ioctl,
|
.unlocked_ioctl = f2fs_ioctl,
|
||||||
};
|
};
|
||||||
|
|
104
fs/fat/dir.c
104
fs/fat/dir.c
|
@ -543,6 +543,7 @@ end_of_dir:
|
||||||
EXPORT_SYMBOL_GPL(fat_search_long);
|
EXPORT_SYMBOL_GPL(fat_search_long);
|
||||||
|
|
||||||
struct fat_ioctl_filldir_callback {
|
struct fat_ioctl_filldir_callback {
|
||||||
|
struct dir_context ctx;
|
||||||
void __user *dirent;
|
void __user *dirent;
|
||||||
int result;
|
int result;
|
||||||
/* for dir ioctl */
|
/* for dir ioctl */
|
||||||
|
@ -552,8 +553,9 @@ struct fat_ioctl_filldir_callback {
|
||||||
int short_len;
|
int short_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
|
static int __fat_readdir(struct inode *inode, struct file *file,
|
||||||
filldir_t filldir, int short_only, int both)
|
struct dir_context *ctx, int short_only,
|
||||||
|
struct fat_ioctl_filldir_callback *both)
|
||||||
{
|
{
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct msdos_sb_info *sbi = MSDOS_SB(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];
|
unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
||||||
int isvfat = sbi->options.isvfat;
|
int isvfat = sbi->options.isvfat;
|
||||||
const char *fill_name = NULL;
|
const char *fill_name = NULL;
|
||||||
unsigned long inum;
|
int fake_offset = 0;
|
||||||
unsigned long lpos, dummy, *furrfu = &lpos;
|
|
||||||
loff_t cpos;
|
loff_t cpos;
|
||||||
int short_len = 0, fill_len = 0;
|
int short_len = 0, fill_len = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&sbi->s_lock);
|
mutex_lock(&sbi->s_lock);
|
||||||
|
|
||||||
cpos = filp->f_pos;
|
cpos = ctx->pos;
|
||||||
/* Fake . and .. for the root directory. */
|
/* Fake . and .. for the root directory. */
|
||||||
if (inode->i_ino == MSDOS_ROOT_INO) {
|
if (inode->i_ino == MSDOS_ROOT_INO) {
|
||||||
while (cpos < 2) {
|
if (!dir_emit_dots(file, ctx))
|
||||||
if (filldir(dirent, "..", cpos+1, cpos,
|
goto out;
|
||||||
MSDOS_ROOT_INO, DT_DIR) < 0)
|
if (ctx->pos == 2) {
|
||||||
goto out;
|
fake_offset = 1;
|
||||||
cpos++;
|
|
||||||
filp->f_pos++;
|
|
||||||
}
|
|
||||||
if (cpos == 2) {
|
|
||||||
dummy = 2;
|
|
||||||
furrfu = &dummy;
|
|
||||||
cpos = 0;
|
cpos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,7 +614,7 @@ parse_record:
|
||||||
int status = fat_parse_long(inode, &cpos, &bh, &de,
|
int status = fat_parse_long(inode, &cpos, &bh, &de,
|
||||||
&unicode, &nr_slots);
|
&unicode, &nr_slots);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
filp->f_pos = cpos;
|
ctx->pos = cpos;
|
||||||
ret = status;
|
ret = status;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (status == PARSE_INVALID)
|
} else if (status == PARSE_INVALID)
|
||||||
|
@ -639,6 +634,19 @@ parse_record:
|
||||||
/* !both && !short_only, so we don't need shortname. */
|
/* !both && !short_only, so we don't need shortname. */
|
||||||
if (!both)
|
if (!both)
|
||||||
goto start_filldir;
|
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 @@ parse_record:
|
||||||
if (short_len == 0)
|
if (short_len == 0)
|
||||||
goto record_end;
|
goto record_end;
|
||||||
|
|
||||||
if (nr_slots) {
|
fill_name = bufname;
|
||||||
/* hack for fat_ioctl_filldir() */
|
fill_len = short_len;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_filldir:
|
start_filldir:
|
||||||
lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
|
if (!fake_offset)
|
||||||
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
|
ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
|
||||||
inum = inode->i_ino;
|
|
||||||
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
|
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
|
||||||
inum = parent_ino(filp->f_path.dentry);
|
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 {
|
} else {
|
||||||
|
unsigned long inum;
|
||||||
loff_t i_pos = fat_make_i_pos(sb, bh, de);
|
loff_t i_pos = fat_make_i_pos(sb, bh, de);
|
||||||
struct inode *tmp = fat_iget(sb, i_pos);
|
struct inode *tmp = fat_iget(sb, i_pos);
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
|
@ -675,18 +676,17 @@ start_filldir:
|
||||||
iput(tmp);
|
iput(tmp);
|
||||||
} else
|
} else
|
||||||
inum = iunique(sb, MSDOS_ROOT_INO);
|
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:
|
record_end:
|
||||||
furrfu = &lpos;
|
fake_offset = 0;
|
||||||
filp->f_pos = cpos;
|
ctx->pos = cpos;
|
||||||
goto get_new;
|
goto get_new;
|
||||||
end_of_dir:
|
end_of_dir:
|
||||||
filp->f_pos = cpos;
|
ctx->pos = cpos;
|
||||||
fill_failed:
|
fill_failed:
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
if (unicode)
|
if (unicode)
|
||||||
|
@ -696,10 +696,9 @@ out:
|
||||||
return ret;
|
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(file_inode(file), file, ctx, 0, NULL);
|
||||||
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
|
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
|
||||||
|
@ -755,20 +754,25 @@ efault: \
|
||||||
|
|
||||||
FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)
|
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,
|
void __user *dirent, filldir_t filldir,
|
||||||
int short_only, int both)
|
int short_only, int both)
|
||||||
{
|
{
|
||||||
struct fat_ioctl_filldir_callback buf;
|
struct fat_ioctl_filldir_callback buf = {
|
||||||
|
.ctx.actor = filldir,
|
||||||
|
.dirent = dirent
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
buf.dirent = dirent;
|
buf.dirent = dirent;
|
||||||
buf.result = 0;
|
buf.result = 0;
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
|
buf.ctx.pos = file->f_pos;
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
if (!IS_DEADDIR(inode)) {
|
if (!IS_DEADDIR(inode)) {
|
||||||
ret = __fat_readdir(inode, filp, &buf, filldir,
|
ret = __fat_readdir(inode, file, &buf.ctx,
|
||||||
short_only, both);
|
short_only, both ? &buf : NULL);
|
||||||
|
file->f_pos = buf.ctx.pos;
|
||||||
}
|
}
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
if (ret >= 0)
|
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 = {
|
const struct file_operations fat_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = fat_readdir,
|
.iterate = fat_readdir,
|
||||||
.unlocked_ioctl = fat_dir_ioctl,
|
.unlocked_ioctl = fat_dir_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = fat_compat_dir_ioctl,
|
.compat_ioctl = fat_compat_dir_ioctl,
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
|
|
||||||
static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int);
|
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 = {
|
const struct inode_operations vxfs_dir_inode_ops = {
|
||||||
.lookup = vxfs_lookup,
|
.lookup = vxfs_lookup,
|
||||||
|
@ -58,7 +58,7 @@ const struct inode_operations vxfs_dir_inode_ops = {
|
||||||
const struct file_operations vxfs_dir_operations = {
|
const struct file_operations vxfs_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.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.
|
* Zero.
|
||||||
*/
|
*/
|
||||||
static int
|
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 inode *ip = file_inode(fp);
|
||||||
struct super_block *sbp = ip->i_sb;
|
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;
|
u_long page, npages, block, pblocks, nblocks, offset;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
|
|
||||||
switch ((long)fp->f_pos) {
|
if (ctx->pos == 0) {
|
||||||
case 0:
|
if (!dir_emit_dot(fp, ctx))
|
||||||
if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
|
return 0;
|
||||||
goto out;
|
ctx->pos = 1;
|
||||||
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 == 1) {
|
||||||
pos = fp->f_pos - 2;
|
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))
|
if (pos > VXFS_DIRROUND(ip->i_size))
|
||||||
return 0;
|
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;
|
block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
|
||||||
|
|
||||||
for (; page < npages; page++, block = 0) {
|
for (; page < npages; page++, block = 0) {
|
||||||
caddr_t kaddr;
|
char *kaddr;
|
||||||
struct page *pp;
|
struct page *pp;
|
||||||
|
|
||||||
pp = vxfs_get_page(ip->i_mapping, page);
|
pp = vxfs_get_page(ip->i_mapping, page);
|
||||||
if (IS_ERR(pp))
|
if (IS_ERR(pp))
|
||||||
continue;
|
continue;
|
||||||
kaddr = (caddr_t)page_address(pp);
|
kaddr = (char *)page_address(pp);
|
||||||
|
|
||||||
for (; block <= nblocks && block <= pblocks; block++) {
|
for (; block <= nblocks && block <= pblocks; block++) {
|
||||||
caddr_t baddr, limit;
|
char *baddr, *limit;
|
||||||
struct vxfs_dirblk *dbp;
|
struct vxfs_dirblk *dbp;
|
||||||
struct vxfs_direct *de;
|
struct vxfs_direct *de;
|
||||||
|
|
||||||
|
@ -292,21 +289,18 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
|
||||||
(kaddr + offset) :
|
(kaddr + offset) :
|
||||||
(baddr + VXFS_DIRBLKOV(dbp)));
|
(baddr + VXFS_DIRBLKOV(dbp)));
|
||||||
|
|
||||||
for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
|
for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
|
||||||
int over;
|
|
||||||
|
|
||||||
if (!de->d_reclen)
|
if (!de->d_reclen)
|
||||||
break;
|
break;
|
||||||
if (!de->d_ino)
|
if (!de->d_ino)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
offset = (caddr_t)de - kaddr;
|
offset = (char *)de - kaddr;
|
||||||
over = filler(retp, de->d_name, de->d_namelen,
|
ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
|
||||||
((page << PAGE_CACHE_SHIFT) | offset) + 2,
|
if (!dir_emit(ctx, de->d_name, de->d_namelen,
|
||||||
de->d_ino, DT_UNKNOWN);
|
de->d_ino, DT_UNKNOWN)) {
|
||||||
if (over) {
|
|
||||||
vxfs_put_page(pp);
|
vxfs_put_page(pp);
|
||||||
goto done;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
@ -314,9 +308,6 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
|
||||||
vxfs_put_page(pp);
|
vxfs_put_page(pp);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
|
||||||
done:
|
|
||||||
fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
|
|
||||||
out:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <linux/slab.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_conn *fc = get_fuse_conn(dir);
|
||||||
struct fuse_inode *fi = get_fuse_inode(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;
|
return true;
|
||||||
if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
|
if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
|
||||||
return true;
|
return true;
|
||||||
if (filp->f_pos == 0)
|
if (ctx->pos == 0)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
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,
|
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) {
|
while (nbytes >= FUSE_NAME_OFFSET) {
|
||||||
struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
|
struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
|
||||||
size_t reclen = FUSE_DIRENT_SIZE(dirent);
|
size_t reclen = FUSE_DIRENT_SIZE(dirent);
|
||||||
int over;
|
|
||||||
if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
|
if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (reclen > nbytes)
|
if (reclen > nbytes)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
over = filldir(dstbuf, dirent->name, dirent->namelen,
|
if (!dir_emit(ctx, dirent->name, dirent->namelen,
|
||||||
file->f_pos, dirent->ino, dirent->type);
|
dirent->ino, dirent->type))
|
||||||
if (over)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf += reclen;
|
buf += reclen;
|
||||||
nbytes -= reclen;
|
nbytes -= reclen;
|
||||||
file->f_pos = dirent->off;
|
ctx->pos = dirent->off;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1284,7 +1282,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_dirplusfile(char *buf, size_t nbytes, 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_direntplus *direntplus;
|
||||||
struct fuse_dirent *dirent;
|
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
|
we need to send a FORGET for each of those
|
||||||
which we did not link.
|
which we did not link.
|
||||||
*/
|
*/
|
||||||
over = filldir(dstbuf, dirent->name, dirent->namelen,
|
over = !dir_emit(ctx, dirent->name, dirent->namelen,
|
||||||
file->f_pos, dirent->ino,
|
dirent->ino, dirent->type);
|
||||||
dirent->type);
|
ctx->pos = dirent->off;
|
||||||
file->f_pos = dirent->off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += reclen;
|
buf += reclen;
|
||||||
|
@ -1326,7 +1323,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
|
||||||
return 0;
|
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;
|
int plus, err;
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
@ -1349,17 +1346,17 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
plus = fuse_use_readdirplus(inode, file);
|
plus = fuse_use_readdirplus(inode, ctx);
|
||||||
req->out.argpages = 1;
|
req->out.argpages = 1;
|
||||||
req->num_pages = 1;
|
req->num_pages = 1;
|
||||||
req->pages[0] = page;
|
req->pages[0] = page;
|
||||||
req->page_descs[0].length = PAGE_SIZE;
|
req->page_descs[0].length = PAGE_SIZE;
|
||||||
if (plus) {
|
if (plus) {
|
||||||
attr_version = fuse_get_attr_version(fc);
|
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);
|
FUSE_READDIRPLUS);
|
||||||
} else {
|
} else {
|
||||||
fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
|
fuse_read_fill(req, file, ctx->pos, PAGE_SIZE,
|
||||||
FUSE_READDIR);
|
FUSE_READDIR);
|
||||||
}
|
}
|
||||||
fuse_request_send(fc, req);
|
fuse_request_send(fc, req);
|
||||||
|
@ -1369,11 +1366,11 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (plus) {
|
if (plus) {
|
||||||
err = parse_dirplusfile(page_address(page), nbytes,
|
err = parse_dirplusfile(page_address(page), nbytes,
|
||||||
file, dstbuf, filldir,
|
file, ctx,
|
||||||
attr_version);
|
attr_version);
|
||||||
} else {
|
} else {
|
||||||
err = parse_dirfile(page_address(page), nbytes, file,
|
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 = {
|
static const struct file_operations fuse_dir_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = fuse_readdir,
|
.iterate = fuse_readdir,
|
||||||
.open = fuse_dir_open,
|
.open = fuse_dir_open,
|
||||||
.release = fuse_dir_release,
|
.release = fuse_dir_release,
|
||||||
.fsync = fuse_dir_fsync,
|
.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
|
* do_filldir_main - read out directory entries
|
||||||
* @dip: The GFS2 inode
|
* @dip: The GFS2 inode
|
||||||
* @offset: The offset in the file to read from
|
* @ctx: what to feed the entries to
|
||||||
* @opaque: opaque data to pass to filldir
|
|
||||||
* @filldir: The function to pass entries to
|
|
||||||
* @darr: an array of struct gfs2_dirent pointers to read
|
* @darr: an array of struct gfs2_dirent pointers to read
|
||||||
* @entries: the number of entries in darr
|
* @entries: the number of entries in darr
|
||||||
* @copied: pointer to int that's non-zero if a entry has been copied out
|
* @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
|
* the possibility that they will fall into different readdir buffers or
|
||||||
* that someone will want to seek to that location.
|
* 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,
|
static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx,
|
||||||
void *opaque, filldir_t filldir,
|
|
||||||
const struct gfs2_dirent **darr, u32 entries,
|
const struct gfs2_dirent **darr, u32 entries,
|
||||||
int *copied)
|
int *copied)
|
||||||
{
|
{
|
||||||
|
@ -1236,7 +1233,6 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
|
||||||
u64 off, off_next;
|
u64 off, off_next;
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
int run = 0;
|
int run = 0;
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);
|
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 = be32_to_cpu(dent_next->de_hash);
|
||||||
off_next = gfs2_disk_hash2offset(off_next);
|
off_next = gfs2_disk_hash2offset(off_next);
|
||||||
|
|
||||||
if (off < *offset)
|
if (off < ctx->pos)
|
||||||
continue;
|
continue;
|
||||||
*offset = off;
|
ctx->pos = off;
|
||||||
|
|
||||||
if (off_next == off) {
|
if (off_next == off) {
|
||||||
if (*copied && !run)
|
if (*copied && !run)
|
||||||
|
@ -1264,26 +1260,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
|
||||||
} else
|
} else
|
||||||
run = 0;
|
run = 0;
|
||||||
} else {
|
} else {
|
||||||
if (off < *offset)
|
if (off < ctx->pos)
|
||||||
continue;
|
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),
|
be16_to_cpu(dent->de_name_len),
|
||||||
off, be64_to_cpu(dent->de_inum.no_addr),
|
be64_to_cpu(dent->de_inum.no_addr),
|
||||||
be16_to_cpu(dent->de_type));
|
be16_to_cpu(dent->de_type)))
|
||||||
if (error)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
*copied = 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
|
do_filldir fxn, we get the next entry instead of the last one in the
|
||||||
current leaf */
|
current leaf */
|
||||||
|
|
||||||
(*offset)++;
|
ctx->pos++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1307,8 +1302,8 @@ static void gfs2_free_sort_buffer(void *ptr)
|
||||||
kfree(ptr);
|
kfree(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
|
||||||
filldir_t filldir, int *copied, unsigned *depth,
|
int *copied, unsigned *depth,
|
||||||
u64 leaf_no)
|
u64 leaf_no)
|
||||||
{
|
{
|
||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
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);
|
} while(lfn);
|
||||||
|
|
||||||
BUG_ON(entries2 != entries);
|
BUG_ON(entries2 != entries);
|
||||||
error = do_filldir_main(ip, offset, opaque, filldir, darr,
|
error = do_filldir_main(ip, ctx, darr, entries, copied);
|
||||||
entries, copied);
|
|
||||||
out_free:
|
out_free:
|
||||||
for(i = 0; i < leaf; i++)
|
for(i = 0; i < leaf; i++)
|
||||||
brelse(larr[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
|
* dir_e_read - Reads the entries from a directory into a filldir buffer
|
||||||
* @dip: dinode pointer
|
* @dip: dinode pointer
|
||||||
* @offset: the hash of the last entry read shifted to the right once
|
* @ctx: actor to feed the entries to
|
||||||
* @opaque: buffer for the filldir function to fill
|
|
||||||
* @filldir: points to the filldir function to use
|
|
||||||
*
|
*
|
||||||
* Returns: errno
|
* Returns: errno
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
|
static int dir_e_read(struct inode *inode, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct file_ra_state *f_ra)
|
struct file_ra_state *f_ra)
|
||||||
{
|
{
|
||||||
struct gfs2_inode *dip = GFS2_I(inode);
|
struct gfs2_inode *dip = GFS2_I(inode);
|
||||||
u32 hsize, len = 0;
|
u32 hsize, len = 0;
|
||||||
|
@ -1465,7 +1457,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
|
||||||
unsigned depth = 0;
|
unsigned depth = 0;
|
||||||
|
|
||||||
hsize = 1 << dip->i_depth;
|
hsize = 1 << dip->i_depth;
|
||||||
hash = gfs2_dir_offset2hash(*offset);
|
hash = gfs2_dir_offset2hash(ctx->pos);
|
||||||
index = hash >> (32 - dip->i_depth);
|
index = hash >> (32 - dip->i_depth);
|
||||||
|
|
||||||
if (dip->i_hash_cache == NULL)
|
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);
|
gfs2_dir_readahead(inode, hsize, index, f_ra);
|
||||||
|
|
||||||
while (index < hsize) {
|
while (index < hsize) {
|
||||||
error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
|
error = gfs2_dir_read_leaf(inode, ctx,
|
||||||
&copied, &depth,
|
&copied, &depth,
|
||||||
be64_to_cpu(lp[index]));
|
be64_to_cpu(lp[index]));
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -1492,8 +1484,8 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
|
int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct file_ra_state *f_ra)
|
struct file_ra_state *f_ra)
|
||||||
{
|
{
|
||||||
struct gfs2_inode *dip = GFS2_I(inode);
|
struct gfs2_inode *dip = GFS2_I(inode);
|
||||||
struct gfs2_sbd *sdp = GFS2_SB(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;
|
return 0;
|
||||||
|
|
||||||
if (dip->i_diskflags & GFS2_DIF_EXHASH)
|
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)) {
|
if (!gfs2_is_stuffed(dip)) {
|
||||||
gfs2_consist_inode(dip);
|
gfs2_consist_inode(dip);
|
||||||
|
@ -1539,7 +1531,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
|
||||||
error = -EIO;
|
error = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
error = do_filldir_main(dip, offset, opaque, filldir, darr,
|
error = do_filldir_main(dip, ctx, darr,
|
||||||
dip->i_entries, &copied);
|
dip->i_entries, &copied);
|
||||||
out:
|
out:
|
||||||
kfree(darr);
|
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,
|
extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
|
||||||
const struct gfs2_inode *ip);
|
const struct gfs2_inode *ip);
|
||||||
extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry);
|
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,
|
extern int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
|
||||||
filldir_t filldir, struct file_ra_state *f_ra);
|
struct file_ra_state *f_ra);
|
||||||
extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
|
extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
|
||||||
const struct gfs2_inode *nip, unsigned int new_type);
|
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 get_name_filldir {
|
||||||
|
struct dir_context ctx;
|
||||||
struct gfs2_inum_host inum;
|
struct gfs2_inum_host inum;
|
||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
@ -88,9 +89,11 @@ static int gfs2_get_name(struct dentry *parent, char *name,
|
||||||
struct inode *dir = parent->d_inode;
|
struct inode *dir = parent->d_inode;
|
||||||
struct inode *inode = child->d_inode;
|
struct inode *inode = child->d_inode;
|
||||||
struct gfs2_inode *dip, *ip;
|
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;
|
struct gfs2_holder gh;
|
||||||
u64 offset = 0;
|
|
||||||
int error;
|
int error;
|
||||||
struct file_ra_state f_ra = { .start = 0 };
|
struct file_ra_state f_ra = { .start = 0 };
|
||||||
|
|
||||||
|
@ -106,13 +109,12 @@ static int gfs2_get_name(struct dentry *parent, char *name,
|
||||||
*name = 0;
|
*name = 0;
|
||||||
gnfd.inum.no_addr = ip->i_no_addr;
|
gnfd.inum.no_addr = ip->i_no_addr;
|
||||||
gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
|
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);
|
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||||
if (error)
|
if (error)
|
||||||
return 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);
|
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
|
* @file: The directory to read from
|
||||||
* @dirent: Buffer for dirents
|
* @ctx: What to feed directory entries to
|
||||||
* @filldir: Function used to do the copying
|
|
||||||
*
|
*
|
||||||
* Returns: errno
|
* 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 inode *dir = file->f_mapping->host;
|
||||||
struct gfs2_inode *dip = GFS2_I(dir);
|
struct gfs2_inode *dip = GFS2_I(dir);
|
||||||
struct gfs2_holder d_gh;
|
struct gfs2_holder d_gh;
|
||||||
u64 offset = file->f_pos;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
gfs2_holder_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
|
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
|
||||||
error = gfs2_glock_nq(&d_gh);
|
if (error)
|
||||||
if (error) {
|
|
||||||
gfs2_holder_uninit(&d_gh);
|
|
||||||
return 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);
|
gfs2_glock_dq_uninit(&d_gh);
|
||||||
|
|
||||||
file->f_pos = offset;
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1048,7 +1041,7 @@ const struct file_operations gfs2_file_fops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations gfs2_dir_fops = {
|
const struct file_operations gfs2_dir_fops = {
|
||||||
.readdir = gfs2_readdir,
|
.iterate = gfs2_readdir,
|
||||||
.unlocked_ioctl = gfs2_ioctl,
|
.unlocked_ioctl = gfs2_ioctl,
|
||||||
.open = gfs2_open,
|
.open = gfs2_open,
|
||||||
.release = gfs2_release,
|
.release = gfs2_release,
|
||||||
|
@ -1078,7 +1071,7 @@ const struct file_operations gfs2_file_fops_nolock = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations gfs2_dir_fops_nolock = {
|
const struct file_operations gfs2_dir_fops_nolock = {
|
||||||
.readdir = gfs2_readdir,
|
.iterate = gfs2_readdir,
|
||||||
.unlocked_ioctl = gfs2_ioctl,
|
.unlocked_ioctl = gfs2_ioctl,
|
||||||
.open = gfs2_open,
|
.open = gfs2_open,
|
||||||
.release = gfs2_release,
|
.release = gfs2_release,
|
||||||
|
|
49
fs/hfs/dir.c
49
fs/hfs/dir.c
|
@ -51,9 +51,9 @@ done:
|
||||||
/*
|
/*
|
||||||
* hfs_readdir
|
* 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;
|
struct super_block *sb = inode->i_sb;
|
||||||
int len, err;
|
int len, err;
|
||||||
char strbuf[HFS_MAX_NAMELEN];
|
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;
|
struct hfs_readdir_data *rd;
|
||||||
u16 type;
|
u16 type;
|
||||||
|
|
||||||
if (filp->f_pos >= inode->i_size)
|
if (ctx->pos >= inode->i_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
|
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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
switch ((u32)filp->f_pos) {
|
if (ctx->pos == 0) {
|
||||||
case 0:
|
|
||||||
/* This is completely artificial... */
|
/* This is completely artificial... */
|
||||||
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
|
if (!dir_emit_dot(file, ctx))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos++;
|
ctx->pos = 1;
|
||||||
/* fall through */
|
}
|
||||||
case 1:
|
if (ctx->pos == 1) {
|
||||||
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
|
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -97,18 +96,16 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
// err = -EIO;
|
// err = -EIO;
|
||||||
// goto out;
|
// goto out;
|
||||||
//}
|
//}
|
||||||
if (filldir(dirent, "..", 2, 1,
|
if (!dir_emit(ctx, "..", 2,
|
||||||
be32_to_cpu(entry.thread.ParID), DT_DIR))
|
be32_to_cpu(entry.thread.ParID), DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos++;
|
ctx->pos = 2;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
if (ctx->pos >= inode->i_size)
|
||||||
|
goto out;
|
||||||
|
err = hfs_brec_goto(&fd, ctx->pos - 1);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
|
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;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filldir(dirent, strbuf, len, filp->f_pos,
|
if (!dir_emit(ctx, strbuf, len,
|
||||||
be32_to_cpu(entry.dir.DirID), DT_DIR))
|
be32_to_cpu(entry.dir.DirID), DT_DIR))
|
||||||
break;
|
break;
|
||||||
} else if (type == HFS_CDR_FIL) {
|
} else if (type == HFS_CDR_FIL) {
|
||||||
|
@ -140,7 +137,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filldir(dirent, strbuf, len, filp->f_pos,
|
if (!dir_emit(ctx, strbuf, len,
|
||||||
be32_to_cpu(entry.file.FlNum), DT_REG))
|
be32_to_cpu(entry.file.FlNum), DT_REG))
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,22 +145,22 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
if (filp->f_pos >= inode->i_size)
|
if (ctx->pos >= inode->i_size)
|
||||||
goto out;
|
goto out;
|
||||||
err = hfs_brec_goto(&fd, 1);
|
err = hfs_brec_goto(&fd, 1);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
rd = filp->private_data;
|
rd = file->private_data;
|
||||||
if (!rd) {
|
if (!rd) {
|
||||||
rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
|
rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
|
||||||
if (!rd) {
|
if (!rd) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
filp->private_data = rd;
|
file->private_data = rd;
|
||||||
rd->file = filp;
|
rd->file = file;
|
||||||
list_add(&rd->list, &HFS_I(inode)->open_dir_list);
|
list_add(&rd->list, &HFS_I(inode)->open_dir_list);
|
||||||
}
|
}
|
||||||
memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
|
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 = {
|
const struct file_operations hfs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = hfs_readdir,
|
.iterate = hfs_readdir,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.release = hfs_dir_release,
|
.release = hfs_dir_release,
|
||||||
};
|
};
|
||||||
|
|
|
@ -121,9 +121,9 @@ fail:
|
||||||
return ERR_PTR(err);
|
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;
|
struct super_block *sb = inode->i_sb;
|
||||||
int len, err;
|
int len, err;
|
||||||
char strbuf[HFSPLUS_MAX_STRLEN + 1];
|
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;
|
struct hfsplus_readdir_data *rd;
|
||||||
u16 type;
|
u16 type;
|
||||||
|
|
||||||
if (filp->f_pos >= inode->i_size)
|
if (file->f_pos >= inode->i_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
|
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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
switch ((u32)filp->f_pos) {
|
if (ctx->pos == 0) {
|
||||||
case 0:
|
|
||||||
/* This is completely artificial... */
|
/* This is completely artificial... */
|
||||||
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
|
if (!dir_emit_dot(file, ctx))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos++;
|
ctx->pos = 1;
|
||||||
/* fall through */
|
}
|
||||||
case 1:
|
if (ctx->pos == 1) {
|
||||||
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
|
if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -168,19 +167,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filldir(dirent, "..", 2, 1,
|
if (!dir_emit(ctx, "..", 2,
|
||||||
be32_to_cpu(entry.thread.parentID), DT_DIR))
|
be32_to_cpu(entry.thread.parentID), DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos++;
|
ctx->pos = 2;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
if (ctx->pos >= inode->i_size)
|
||||||
|
goto out;
|
||||||
|
err = hfs_brec_goto(&fd, ctx->pos - 1);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) {
|
if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) {
|
||||||
pr_err("walked past end of dir\n");
|
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 ==
|
HFSPLUS_SB(sb)->hidden_dir->i_ino ==
|
||||||
be32_to_cpu(entry.folder.id))
|
be32_to_cpu(entry.folder.id))
|
||||||
goto next;
|
goto next;
|
||||||
if (filldir(dirent, strbuf, len, filp->f_pos,
|
if (!dir_emit(ctx, strbuf, len,
|
||||||
be32_to_cpu(entry.folder.id), DT_DIR))
|
be32_to_cpu(entry.folder.id), DT_DIR))
|
||||||
break;
|
break;
|
||||||
} else if (type == HFSPLUS_FILE) {
|
} else if (type == HFSPLUS_FILE) {
|
||||||
|
@ -220,7 +216,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filldir(dirent, strbuf, len, filp->f_pos,
|
if (!dir_emit(ctx, strbuf, len,
|
||||||
be32_to_cpu(entry.file.id), DT_REG))
|
be32_to_cpu(entry.file.id), DT_REG))
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,22 +225,22 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
if (filp->f_pos >= inode->i_size)
|
if (ctx->pos >= inode->i_size)
|
||||||
goto out;
|
goto out;
|
||||||
err = hfs_brec_goto(&fd, 1);
|
err = hfs_brec_goto(&fd, 1);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
rd = filp->private_data;
|
rd = file->private_data;
|
||||||
if (!rd) {
|
if (!rd) {
|
||||||
rd = kmalloc(sizeof(struct hfsplus_readdir_data), GFP_KERNEL);
|
rd = kmalloc(sizeof(struct hfsplus_readdir_data), GFP_KERNEL);
|
||||||
if (!rd) {
|
if (!rd) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
filp->private_data = rd;
|
file->private_data = rd;
|
||||||
rd->file = filp;
|
rd->file = file;
|
||||||
list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
|
list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
|
||||||
}
|
}
|
||||||
memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
|
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 = {
|
const struct file_operations hfsplus_dir_operations = {
|
||||||
.fsync = hfsplus_file_fsync,
|
.fsync = hfsplus_file_fsync,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = hfsplus_readdir,
|
.iterate = hfsplus_readdir,
|
||||||
.unlocked_ioctl = hfsplus_ioctl,
|
.unlocked_ioctl = hfsplus_ioctl,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.release = hfsplus_dir_release,
|
.release = hfsplus_dir_release,
|
||||||
|
|
|
@ -277,7 +277,7 @@ static const struct super_operations hostfs_sbops = {
|
||||||
.show_options = hostfs_show_options,
|
.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;
|
void *dir;
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -292,12 +292,11 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
|
||||||
__putname(name);
|
__putname(name);
|
||||||
if (dir == NULL)
|
if (dir == NULL)
|
||||||
return -error;
|
return -error;
|
||||||
next = file->f_pos;
|
next = ctx->pos;
|
||||||
while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
|
while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
|
||||||
error = (*filldir)(ent, name, len, file->f_pos,
|
if (!dir_emit(ctx, name, len, ino, type))
|
||||||
ino, type);
|
break;
|
||||||
if (error) break;
|
ctx->pos = next;
|
||||||
file->f_pos = next;
|
|
||||||
}
|
}
|
||||||
close_dir(dir);
|
close_dir(dir);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -393,7 +392,7 @@ static const struct file_operations hostfs_file_fops = {
|
||||||
|
|
||||||
static const struct file_operations hostfs_dir_fops = {
|
static const struct file_operations hostfs_dir_fops = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.readdir = hostfs_readdir,
|
.iterate = hostfs_readdir,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,14 +57,14 @@ fail:
|
||||||
return -ESPIPE;
|
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 hpfs_inode_info *hpfs_inode = hpfs_i(inode);
|
||||||
struct quad_buffer_head qbh;
|
struct quad_buffer_head qbh;
|
||||||
struct hpfs_dirent *de;
|
struct hpfs_dirent *de;
|
||||||
int lc;
|
int lc;
|
||||||
long old_pos;
|
loff_t next_pos;
|
||||||
unsigned char *tempname;
|
unsigned char *tempname;
|
||||||
int c1, c2 = 0;
|
int c1, c2 = 0;
|
||||||
int ret = 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;
|
lc = hpfs_sb(inode->i_sb)->sb_lowercase;
|
||||||
if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */
|
if (ctx->pos == 12) { /* diff -r requires this (note, that diff -r */
|
||||||
filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */
|
ctx->pos = 13; /* also fails on msdos filesystem in 2.0) */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 13) {
|
if (ctx->pos == 13) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
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?
|
accepted by filldir, but what can I do?
|
||||||
maybe killall -9 ls helps */
|
maybe killall -9 ls helps */
|
||||||
if (hpfs_sb(inode->i_sb)->sb_chk)
|
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;
|
ret = -EFSERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 12)
|
if (ctx->pos == 12)
|
||||||
goto out;
|
goto out;
|
||||||
if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
|
if (ctx->pos == 3 || ctx->pos == 4 || ctx->pos == 5) {
|
||||||
printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
|
printk("HPFS: warning: pos==%d\n",(int)ctx->pos);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 0) {
|
if (ctx->pos == 0) {
|
||||||
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
|
if (!dir_emit_dot(file, ctx))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos = 11;
|
ctx->pos = 11;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 11) {
|
if (ctx->pos == 11) {
|
||||||
if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0)
|
if (!dir_emit(ctx, "..", 2, hpfs_inode->i_parent_dir, DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
filp->f_pos = 1;
|
ctx->pos = 1;
|
||||||
}
|
}
|
||||||
if (filp->f_pos == 1) {
|
if (ctx->pos == 1) {
|
||||||
filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
|
ctx->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);
|
hpfs_add_pos(inode, &file->f_pos);
|
||||||
filp->f_version = inode->i_version;
|
file->f_version = inode->i_version;
|
||||||
}
|
}
|
||||||
old_pos = filp->f_pos;
|
next_pos = ctx->pos;
|
||||||
if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
|
if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) {
|
||||||
|
ctx->pos = next_pos;
|
||||||
ret = -EIOERROR;
|
ret = -EIOERROR;
|
||||||
goto out;
|
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 (hpfs_sb(inode->i_sb)->sb_chk) {
|
||||||
if (de->first && !de->last && (de->namelen != 2
|
if (de->first && !de->last && (de->namelen != 2
|
||||||
|| de ->name[0] != 1 || de->name[1] != 1))
|
|| 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))
|
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);
|
hpfs_brelse4(&qbh);
|
||||||
|
ctx->pos = next_pos;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
|
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) {
|
if (!dir_emit(ctx, tempname, de->namelen, le32_to_cpu(de->fnode), DT_UNKNOWN)) {
|
||||||
filp->f_pos = old_pos;
|
|
||||||
if (tempname != de->name) kfree(tempname);
|
if (tempname != de->name) kfree(tempname);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ctx->pos = next_pos;
|
||||||
if (tempname != de->name) kfree(tempname);
|
if (tempname != de->name) kfree(tempname);
|
||||||
hpfs_brelse4(&qbh);
|
hpfs_brelse4(&qbh);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +324,7 @@ const struct file_operations hpfs_dir_ops =
|
||||||
{
|
{
|
||||||
.llseek = hpfs_dir_lseek,
|
.llseek = hpfs_dir_lseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = hpfs_readdir,
|
.iterate = hpfs_readdir,
|
||||||
.release = hpfs_dir_release,
|
.release = hpfs_dir_release,
|
||||||
.fsync = hpfs_file_fsync,
|
.fsync = hpfs_file_fsync,
|
||||||
};
|
};
|
||||||
|
|
|
@ -542,8 +542,8 @@ static const struct file_operations hppfs_file_fops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hppfs_dirent {
|
struct hppfs_dirent {
|
||||||
void *vfs_dirent;
|
struct dir_context ctx;
|
||||||
filldir_t filldir;
|
struct dir_context *caller;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -555,34 +555,29 @@ static int hppfs_filldir(void *d, const char *name, int size,
|
||||||
if (file_removed(dirent->dentry, name))
|
if (file_removed(dirent->dentry, name))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset,
|
dirent->caller->pos = dirent->ctx.pos;
|
||||||
inode, type);
|
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 hppfs_private *data = file->private_data;
|
||||||
struct file *proc_file = data->proc_file;
|
struct file *proc_file = data->proc_file;
|
||||||
int (*readdir)(struct file *, void *, filldir_t);
|
struct hppfs_dirent d = {
|
||||||
struct hppfs_dirent dirent = ((struct hppfs_dirent)
|
.ctx.actor = hppfs_filldir,
|
||||||
{ .vfs_dirent = ent,
|
.caller = ctx,
|
||||||
.filldir = filldir,
|
.dentry = file->f_path.dentry
|
||||||
.dentry = file->f_path.dentry
|
};
|
||||||
});
|
|
||||||
int err;
|
int err;
|
||||||
|
proc_file->f_pos = ctx->pos;
|
||||||
readdir = file_inode(proc_file)->i_fop->readdir;
|
err = iterate_dir(proc_file, &d.ctx);
|
||||||
|
ctx->pos = d.ctx.pos;
|
||||||
proc_file->f_pos = file->f_pos;
|
|
||||||
err = (*readdir)(proc_file, &dirent, hppfs_filldir);
|
|
||||||
file->f_pos = proc_file->f_pos;
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations hppfs_dir_fops = {
|
static const struct file_operations hppfs_dir_fops = {
|
||||||
.owner = NULL,
|
.owner = NULL,
|
||||||
.readdir = hppfs_readdir,
|
.iterate = hppfs_readdir,
|
||||||
.open = hppfs_dir_open,
|
.open = hppfs_dir_open,
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
.release = hppfs_release,
|
.release = hppfs_release,
|
||||||
|
|
|
@ -78,8 +78,8 @@ int get_acorn_filename(struct iso_directory_record *de,
|
||||||
/*
|
/*
|
||||||
* This should _really_ be cleaned up some day..
|
* This should _really_ be cleaned up some day..
|
||||||
*/
|
*/
|
||||||
static int do_isofs_readdir(struct inode *inode, struct file *filp,
|
static int do_isofs_readdir(struct inode *inode, struct file *file,
|
||||||
void *dirent, filldir_t filldir,
|
struct dir_context *ctx,
|
||||||
char *tmpname, struct iso_directory_record *tmpde)
|
char *tmpname, struct iso_directory_record *tmpde)
|
||||||
{
|
{
|
||||||
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
|
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 iso_directory_record *de;
|
||||||
struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
|
struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
|
||||||
|
|
||||||
offset = filp->f_pos & (bufsize - 1);
|
offset = ctx->pos & (bufsize - 1);
|
||||||
block = filp->f_pos >> bufbits;
|
block = ctx->pos >> bufbits;
|
||||||
|
|
||||||
while (filp->f_pos < inode->i_size) {
|
while (ctx->pos < inode->i_size) {
|
||||||
int de_len;
|
int de_len;
|
||||||
|
|
||||||
if (!bh) {
|
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 = (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
|
* 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) {
|
if (de_len == 0) {
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
bh = NULL;
|
bh = NULL;
|
||||||
filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
|
ctx->pos = (ctx->pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
|
||||||
block = filp->f_pos >> bufbits;
|
block = ctx->pos >> bufbits;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -164,16 +164,16 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
|
||||||
|
|
||||||
if (de->flags[-sbi->s_high_sierra] & 0x80) {
|
if (de->flags[-sbi->s_high_sierra] & 0x80) {
|
||||||
first_de = 0;
|
first_de = 0;
|
||||||
filp->f_pos += de_len;
|
ctx->pos += de_len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
first_de = 1;
|
first_de = 1;
|
||||||
|
|
||||||
/* Handle the case of the '.' directory */
|
/* Handle the case of the '.' directory */
|
||||||
if (de->name_len[0] == 1 && de->name[0] == 0) {
|
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;
|
break;
|
||||||
filp->f_pos += de_len;
|
ctx->pos += de_len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,10 +181,9 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
|
||||||
|
|
||||||
/* Handle the case of the '..' directory */
|
/* Handle the case of the '..' directory */
|
||||||
if (de->name_len[0] == 1 && de->name[0] == 1) {
|
if (de->name_len[0] == 1 && de->name[0] == 1) {
|
||||||
inode_number = parent_ino(filp->f_path.dentry);
|
if (!dir_emit_dotdot(file, ctx))
|
||||||
if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
|
|
||||||
break;
|
break;
|
||||||
filp->f_pos += de_len;
|
ctx->pos += de_len;
|
||||||
continue;
|
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)) ||
|
if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) ||
|
||||||
(!sbi->s_showassoc &&
|
(!sbi->s_showassoc &&
|
||||||
(de->flags[-sbi->s_high_sierra] & 4))) {
|
(de->flags[-sbi->s_high_sierra] & 4))) {
|
||||||
filp->f_pos += de_len;
|
ctx->pos += de_len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,10 +229,10 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len > 0) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
filp->f_pos += de_len;
|
ctx->pos += de_len;
|
||||||
|
|
||||||
continue;
|
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
|
* handling split directory entries.. The real work is done by
|
||||||
* "do_isofs_readdir()".
|
* "do_isofs_readdir()".
|
||||||
*/
|
*/
|
||||||
static int isofs_readdir(struct file *filp,
|
static int isofs_readdir(struct file *file, struct dir_context *ctx)
|
||||||
void *dirent, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
char *tmpname;
|
char *tmpname;
|
||||||
struct iso_directory_record *tmpde;
|
struct iso_directory_record *tmpde;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
tmpname = (char *)__get_free_page(GFP_KERNEL);
|
tmpname = (char *)__get_free_page(GFP_KERNEL);
|
||||||
if (tmpname == NULL)
|
if (tmpname == NULL)
|
||||||
|
@ -261,7 +259,7 @@ static int isofs_readdir(struct file *filp,
|
||||||
|
|
||||||
tmpde = (struct iso_directory_record *) (tmpname+1024);
|
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);
|
free_page((unsigned long) tmpname);
|
||||||
return result;
|
return result;
|
||||||
|
@ -271,7 +269,7 @@ const struct file_operations isofs_dir_operations =
|
||||||
{
|
{
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = isofs_readdir,
|
.iterate = isofs_readdir,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include "nodelist.h"
|
#include "nodelist.h"
|
||||||
|
|
||||||
static int jffs2_readdir (struct file *, void *, filldir_t);
|
static int jffs2_readdir (struct file *, struct dir_context *);
|
||||||
|
|
||||||
static int jffs2_create (struct inode *,struct dentry *,umode_t,
|
static int jffs2_create (struct inode *,struct dentry *,umode_t,
|
||||||
bool);
|
bool);
|
||||||
|
@ -40,7 +40,7 @@ static int jffs2_rename (struct inode *, struct dentry *,
|
||||||
const struct file_operations jffs2_dir_operations =
|
const struct file_operations jffs2_dir_operations =
|
||||||
{
|
{
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = jffs2_readdir,
|
.iterate = jffs2_readdir,
|
||||||
.unlocked_ioctl=jffs2_ioctl,
|
.unlocked_ioctl=jffs2_ioctl,
|
||||||
.fsync = jffs2_fsync,
|
.fsync = jffs2_fsync,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
|
@ -114,60 +114,40 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
static int jffs2_readdir(struct file *file, struct dir_context *ctx)
|
||||||
{
|
{
|
||||||
struct jffs2_inode_info *f;
|
struct inode *inode = file_inode(file);
|
||||||
struct inode *inode = file_inode(filp);
|
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
|
||||||
struct jffs2_full_dirent *fd;
|
struct jffs2_full_dirent *fd;
|
||||||
unsigned long offset, curofs;
|
unsigned long curofs = 1;
|
||||||
|
|
||||||
jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n",
|
jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino);
|
||||||
file_inode(filp)->i_ino);
|
|
||||||
|
|
||||||
f = JFFS2_INODE_INFO(inode);
|
if (!dir_emit_dots(file, ctx))
|
||||||
|
return 0;
|
||||||
|
|
||||||
offset = filp->f_pos;
|
|
||||||
|
|
||||||
if (offset == 0) {
|
|
||||||
jffs2_dbg(1, "Dirent 0: \".\", ino #%lu\n", inode->i_ino);
|
|
||||||
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
|
|
||||||
goto out;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
if (offset == 1) {
|
|
||||||
unsigned long pino = parent_ino(filp->f_path.dentry);
|
|
||||||
jffs2_dbg(1, "Dirent 1: \"..\", ino #%lu\n", pino);
|
|
||||||
if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
|
|
||||||
goto out;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
curofs=1;
|
|
||||||
mutex_lock(&f->sem);
|
mutex_lock(&f->sem);
|
||||||
for (fd = f->dents; fd; fd = fd->next) {
|
for (fd = f->dents; fd; fd = fd->next) {
|
||||||
|
|
||||||
curofs++;
|
curofs++;
|
||||||
/* First loop: curofs = 2; offset = 2 */
|
/* First loop: curofs = 2; pos = 2 */
|
||||||
if (curofs < offset) {
|
if (curofs < ctx->pos) {
|
||||||
jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
|
jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
|
||||||
fd->name, fd->ino, fd->type, curofs, offset);
|
fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!fd->ino) {
|
if (!fd->ino) {
|
||||||
jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
|
jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
|
||||||
fd->name);
|
fd->name);
|
||||||
offset++;
|
ctx->pos++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
|
jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
|
||||||
offset, fd->name, fd->ino, fd->type);
|
(unsigned long)ctx->pos, fd->name, fd->ino, fd->type);
|
||||||
if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
|
if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type))
|
||||||
break;
|
break;
|
||||||
offset++;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
mutex_unlock(&f->sem);
|
mutex_unlock(&f->sem);
|
||||||
out:
|
|
||||||
filp->f_pos = offset;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3002,9 +3002,9 @@ static inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
|
||||||
* return: offset = (pn, index) of start entry
|
* return: offset = (pn, index) of start entry
|
||||||
* of next jfs_readdir()/dtRead()
|
* of next jfs_readdir()/dtRead()
|
||||||
*/
|
*/
|
||||||
int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
int jfs_readdir(struct file *file, struct dir_context *ctx)
|
||||||
{
|
{
|
||||||
struct inode *ip = file_inode(filp);
|
struct inode *ip = file_inode(file);
|
||||||
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
|
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
loff_t dtpos; /* legacy OS/2 style position */
|
loff_t dtpos; /* legacy OS/2 style position */
|
||||||
|
@ -3033,7 +3033,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
int overflow, fix_page, page_fixed = 0;
|
int overflow, fix_page, page_fixed = 0;
|
||||||
static int unique_pos = 2; /* If we can't fix broken index */
|
static int unique_pos = 2; /* If we can't fix broken index */
|
||||||
|
|
||||||
if (filp->f_pos == DIREND)
|
if (ctx->pos == DIREND)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (DO_INDEX(ip)) {
|
if (DO_INDEX(ip)) {
|
||||||
|
@ -3045,7 +3045,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
*/
|
*/
|
||||||
do_index = 1;
|
do_index = 1;
|
||||||
|
|
||||||
dir_index = (u32) filp->f_pos;
|
dir_index = (u32) ctx->pos;
|
||||||
|
|
||||||
if (dir_index > 1) {
|
if (dir_index > 1) {
|
||||||
struct dir_table_slot dirtab_slot;
|
struct dir_table_slot dirtab_slot;
|
||||||
|
@ -3053,25 +3053,25 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
if (dtEmpty(ip) ||
|
if (dtEmpty(ip) ||
|
||||||
(dir_index >= JFS_IP(ip)->next_index)) {
|
(dir_index >= JFS_IP(ip)->next_index)) {
|
||||||
/* Stale position. Directory has shrunk */
|
/* Stale position. Directory has shrunk */
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
repeat:
|
repeat:
|
||||||
rc = read_index(ip, dir_index, &dirtab_slot);
|
rc = read_index(ip, dir_index, &dirtab_slot);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (dirtab_slot.flag == DIR_INDEX_FREE) {
|
if (dirtab_slot.flag == DIR_INDEX_FREE) {
|
||||||
if (loop_count++ > JFS_IP(ip)->next_index) {
|
if (loop_count++ > JFS_IP(ip)->next_index) {
|
||||||
jfs_err("jfs_readdir detected "
|
jfs_err("jfs_readdir detected "
|
||||||
"infinite loop!");
|
"infinite loop!");
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
dir_index = le32_to_cpu(dirtab_slot.addr2);
|
dir_index = le32_to_cpu(dirtab_slot.addr2);
|
||||||
if (dir_index == -1) {
|
if (dir_index == -1) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
goto repeat;
|
goto repeat;
|
||||||
|
@ -3080,13 +3080,13 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
index = dirtab_slot.slot;
|
index = dirtab_slot.slot;
|
||||||
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (p->header.flag & BT_INTERNAL) {
|
if (p->header.flag & BT_INTERNAL) {
|
||||||
jfs_err("jfs_readdir: bad index table");
|
jfs_err("jfs_readdir: bad index table");
|
||||||
DT_PUTPAGE(mp);
|
DT_PUTPAGE(mp);
|
||||||
filp->f_pos = -1;
|
ctx->pos = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3094,23 +3094,22 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
/*
|
/*
|
||||||
* self "."
|
* self "."
|
||||||
*/
|
*/
|
||||||
filp->f_pos = 0;
|
ctx->pos = 0;
|
||||||
if (filldir(dirent, ".", 1, 0, ip->i_ino,
|
if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
|
||||||
DT_DIR))
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* parent ".."
|
* parent ".."
|
||||||
*/
|
*/
|
||||||
filp->f_pos = 1;
|
ctx->pos = 1;
|
||||||
if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR))
|
if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find first entry of left-most leaf
|
* Find first entry of left-most leaf
|
||||||
*/
|
*/
|
||||||
if (dtEmpty(ip)) {
|
if (dtEmpty(ip)) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3128,23 +3127,19 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
* pn > 0: Real entries, pn=1 -> leftmost page
|
* pn > 0: Real entries, pn=1 -> leftmost page
|
||||||
* pn = index = -1: No more entries
|
* pn = index = -1: No more entries
|
||||||
*/
|
*/
|
||||||
dtpos = filp->f_pos;
|
dtpos = ctx->pos;
|
||||||
if (dtpos == 0) {
|
if (dtpos == 0) {
|
||||||
/* build "." entry */
|
/* build "." entry */
|
||||||
|
if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
|
||||||
if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
|
|
||||||
DT_DIR))
|
|
||||||
return 0;
|
return 0;
|
||||||
dtoffset->index = 1;
|
dtoffset->index = 1;
|
||||||
filp->f_pos = dtpos;
|
ctx->pos = dtpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtoffset->pn == 0) {
|
if (dtoffset->pn == 0) {
|
||||||
if (dtoffset->index == 1) {
|
if (dtoffset->index == 1) {
|
||||||
/* build ".." entry */
|
/* build ".." entry */
|
||||||
|
if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
|
||||||
if (filldir(dirent, "..", 2, filp->f_pos,
|
|
||||||
PARENT(ip), DT_DIR))
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
jfs_err("jfs_readdir called with "
|
jfs_err("jfs_readdir called with "
|
||||||
|
@ -3152,18 +3147,18 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
}
|
}
|
||||||
dtoffset->pn = 1;
|
dtoffset->pn = 1;
|
||||||
dtoffset->index = 0;
|
dtoffset->index = 0;
|
||||||
filp->f_pos = dtpos;
|
ctx->pos = dtpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtEmpty(ip)) {
|
if (dtEmpty(ip)) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) {
|
if ((rc = dtReadNext(ip, &ctx->pos, &btstack))) {
|
||||||
jfs_err("jfs_readdir: unexpected rc = %d "
|
jfs_err("jfs_readdir: unexpected rc = %d "
|
||||||
"from dtReadNext", rc);
|
"from dtReadNext", rc);
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* get start leaf page and index */
|
/* get start leaf page and index */
|
||||||
|
@ -3171,7 +3166,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
/* offset beyond directory eof ? */
|
/* offset beyond directory eof ? */
|
||||||
if (bn < 0) {
|
if (bn < 0) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3180,7 +3175,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
if (dirent_buf == 0) {
|
if (dirent_buf == 0) {
|
||||||
DT_PUTPAGE(mp);
|
DT_PUTPAGE(mp);
|
||||||
jfs_warn("jfs_readdir: __get_free_page failed!");
|
jfs_warn("jfs_readdir: __get_free_page failed!");
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3295,9 +3290,9 @@ skip_one:
|
||||||
|
|
||||||
jfs_dirent = (struct jfs_dirent *) dirent_buf;
|
jfs_dirent = (struct jfs_dirent *) dirent_buf;
|
||||||
while (jfs_dirents--) {
|
while (jfs_dirents--) {
|
||||||
filp->f_pos = jfs_dirent->position;
|
ctx->pos = jfs_dirent->position;
|
||||||
if (filldir(dirent, jfs_dirent->name,
|
if (!dir_emit(ctx, jfs_dirent->name,
|
||||||
jfs_dirent->name_len, filp->f_pos,
|
jfs_dirent->name_len,
|
||||||
jfs_dirent->ino, DT_UNKNOWN))
|
jfs_dirent->ino, DT_UNKNOWN))
|
||||||
goto out;
|
goto out;
|
||||||
jfs_dirent = next_jfs_dirent(jfs_dirent);
|
jfs_dirent = next_jfs_dirent(jfs_dirent);
|
||||||
|
@ -3309,7 +3304,7 @@ skip_one:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overflow && (bn == 0)) {
|
if (!overflow && (bn == 0)) {
|
||||||
filp->f_pos = DIREND;
|
ctx->pos = DIREND;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
|
||||||
ino_t * orig_ino, ino_t new_ino, int flag);
|
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 */
|
#endif /* !_H_JFS_DTREE */
|
||||||
|
|
|
@ -1529,7 +1529,7 @@ const struct inode_operations jfs_dir_inode_operations = {
|
||||||
|
|
||||||
const struct file_operations jfs_dir_operations = {
|
const struct file_operations jfs_dir_operations = {
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = jfs_readdir,
|
.iterate = jfs_readdir,
|
||||||
.fsync = jfs_fsync,
|
.fsync = jfs_fsync,
|
||||||
.unlocked_ioctl = jfs_ioctl,
|
.unlocked_ioctl = jfs_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
|
78
fs/libfs.c
78
fs/libfs.c
|
@ -135,60 +135,40 @@ static inline unsigned char dt_type(struct inode *inode)
|
||||||
* both impossible due to the lock on directory.
|
* both impossible due to the lock on directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
int dcache_readdir(struct file *file, struct dir_context *ctx)
|
||||||
{
|
{
|
||||||
struct dentry *dentry = filp->f_path.dentry;
|
struct dentry *dentry = file->f_path.dentry;
|
||||||
struct dentry *cursor = filp->private_data;
|
struct dentry *cursor = file->private_data;
|
||||||
struct list_head *p, *q = &cursor->d_u.d_child;
|
struct list_head *p, *q = &cursor->d_u.d_child;
|
||||||
ino_t ino;
|
|
||||||
int i = filp->f_pos;
|
|
||||||
|
|
||||||
switch (i) {
|
if (!dir_emit_dots(file, ctx))
|
||||||
case 0:
|
return 0;
|
||||||
ino = dentry->d_inode->i_ino;
|
spin_lock(&dentry->d_lock);
|
||||||
if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
|
if (ctx->pos == 2)
|
||||||
break;
|
list_move(q, &dentry->d_subdirs);
|
||||||
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:
|
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (filp->f_pos == 2)
|
|
||||||
list_move(q, &dentry->d_subdirs);
|
|
||||||
|
|
||||||
for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
|
for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
|
||||||
struct dentry *next;
|
struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
|
||||||
next = list_entry(p, struct dentry, d_u.d_child);
|
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
|
if (!simple_positive(next)) {
|
||||||
if (!simple_positive(next)) {
|
spin_unlock(&next->d_lock);
|
||||||
spin_unlock(&next->d_lock);
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&next->d_lock);
|
spin_unlock(&next->d_lock);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
if (filldir(dirent, next->d_name.name,
|
if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
|
||||||
next->d_name.len, filp->f_pos,
|
next->d_inode->i_ino, dt_type(next->d_inode)))
|
||||||
next->d_inode->i_ino,
|
return 0;
|
||||||
dt_type(next->d_inode)) < 0)
|
spin_lock(&dentry->d_lock);
|
||||||
return 0;
|
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
spin_lock(&dentry->d_lock);
|
/* next is still alive */
|
||||||
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
|
list_move(q, p);
|
||||||
/* next is still alive */
|
spin_unlock(&next->d_lock);
|
||||||
list_move(q, p);
|
p = q;
|
||||||
spin_unlock(&next->d_lock);
|
ctx->pos++;
|
||||||
p = q;
|
|
||||||
filp->f_pos++;
|
|
||||||
}
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
}
|
}
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +182,7 @@ const struct file_operations simple_dir_operations = {
|
||||||
.release = dcache_dir_close,
|
.release = dcache_dir_close,
|
||||||
.llseek = dcache_dir_lseek,
|
.llseek = dcache_dir_lseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = dcache_readdir,
|
.iterate = dcache_readdir,
|
||||||
.fsync = noop_fsync,
|
.fsync = noop_fsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -281,17 +281,23 @@ static int logfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
/* FIXME: readdir currently has it's own dir_walk code. I don't see a good
|
/* FIXME: readdir currently has it's own dir_walk code. I don't see a good
|
||||||
* way to combine the two copies */
|
* way to combine the two copies */
|
||||||
#define IMPLICIT_NODES 2
|
static int logfs_readdir(struct file *file, struct dir_context *ctx)
|
||||||
static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir)
|
|
||||||
{
|
{
|
||||||
struct inode *dir = file_inode(file);
|
struct inode *dir = file_inode(file);
|
||||||
loff_t pos = file->f_pos - IMPLICIT_NODES;
|
loff_t pos;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct logfs_disk_dentry *dd;
|
struct logfs_disk_dentry *dd;
|
||||||
int full;
|
|
||||||
|
|
||||||
|
if (ctx->pos < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!dir_emit_dots(file, ctx))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pos = ctx->pos - 2;
|
||||||
BUG_ON(pos < 0);
|
BUG_ON(pos < 0);
|
||||||
for (;; pos++) {
|
for (;; pos++, ctx->pos++) {
|
||||||
|
bool full;
|
||||||
if (beyond_eof(dir, pos))
|
if (beyond_eof(dir, pos))
|
||||||
break;
|
break;
|
||||||
if (!logfs_exist_block(dir, pos)) {
|
if (!logfs_exist_block(dir, pos)) {
|
||||||
|
@ -306,42 +312,17 @@ static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir)
|
||||||
dd = kmap(page);
|
dd = kmap(page);
|
||||||
BUG_ON(dd->namelen == 0);
|
BUG_ON(dd->namelen == 0);
|
||||||
|
|
||||||
full = filldir(buf, (char *)dd->name, be16_to_cpu(dd->namelen),
|
full = !dir_emit(ctx, (char *)dd->name,
|
||||||
pos, be64_to_cpu(dd->ino), dd->type);
|
be16_to_cpu(dd->namelen),
|
||||||
|
be64_to_cpu(dd->ino), dd->type);
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
if (full)
|
if (full)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->f_pos = pos + IMPLICIT_NODES;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int logfs_readdir(struct file *file, void *buf, filldir_t filldir)
|
|
||||||
{
|
|
||||||
struct inode *inode = file_inode(file);
|
|
||||||
ino_t pino = parent_ino(file->f_dentry);
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (file->f_pos < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (file->f_pos == 0) {
|
|
||||||
if (filldir(buf, ".", 1, 1, inode->i_ino, DT_DIR) < 0)
|
|
||||||
return 0;
|
|
||||||
file->f_pos++;
|
|
||||||
}
|
|
||||||
if (file->f_pos == 1) {
|
|
||||||
if (filldir(buf, "..", 2, 2, pino, DT_DIR) < 0)
|
|
||||||
return 0;
|
|
||||||
file->f_pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = __logfs_readdir(file, buf, filldir);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
|
static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
|
||||||
{
|
{
|
||||||
dd->namelen = cpu_to_be16(name->len);
|
dd->namelen = cpu_to_be16(name->len);
|
||||||
|
@ -814,7 +795,7 @@ const struct inode_operations logfs_dir_iops = {
|
||||||
const struct file_operations logfs_dir_fops = {
|
const struct file_operations logfs_dir_fops = {
|
||||||
.fsync = logfs_fsync,
|
.fsync = logfs_fsync,
|
||||||
.unlocked_ioctl = logfs_ioctl,
|
.unlocked_ioctl = logfs_ioctl,
|
||||||
.readdir = logfs_readdir,
|
.iterate = logfs_readdir,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче