Merge tag 'writeback-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Sep 2013 03:06:40 +0000 (23:06 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Sep 2013 03:06:40 +0000 (23:06 -0400)
Pull writeback fix from Wu Fengguang:
 "A trivial writeback fix"

* tag 'writeback-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux:
  writeback: Do not sort b_io list only because of block device inode

1  2 
fs/block_dev.c
fs/fs-writeback.c
include/linux/fs.h

diff --combined fs/block_dev.c
@@@ -58,24 -58,17 +58,24 @@@ static void bdev_inode_switch_bdi(struc
                        struct backing_dev_info *dst)
  {
        struct backing_dev_info *old = inode->i_data.backing_dev_info;
 +      bool wakeup_bdi = false;
  
        if (unlikely(dst == old))               /* deadlock avoidance */
                return;
        bdi_lock_two(&old->wb, &dst->wb);
        spin_lock(&inode->i_lock);
        inode->i_data.backing_dev_info = dst;
 -      if (inode->i_state & I_DIRTY)
 +      if (inode->i_state & I_DIRTY) {
 +              if (bdi_cap_writeback_dirty(dst) && !wb_has_dirty_io(&dst->wb))
 +                      wakeup_bdi = true;
                list_move(&inode->i_wb_list, &dst->wb.b_dirty);
 +      }
        spin_unlock(&inode->i_lock);
        spin_unlock(&old->wb.list_lock);
        spin_unlock(&dst->wb.list_lock);
 +
 +      if (wakeup_bdi)
 +              bdi_wakeup_thread_delayed(dst);
  }
  
  /* Kill _all_ buffers and pagecache , dirty or not.. */
@@@ -332,10 -325,31 +332,10 @@@ static int blkdev_write_end(struct fil
  static loff_t block_llseek(struct file *file, loff_t offset, int whence)
  {
        struct inode *bd_inode = file->f_mapping->host;
 -      loff_t size;
        loff_t retval;
  
        mutex_lock(&bd_inode->i_mutex);
 -      size = i_size_read(bd_inode);
 -
 -      retval = -EINVAL;
 -      switch (whence) {
 -              case SEEK_END:
 -                      offset += size;
 -                      break;
 -              case SEEK_CUR:
 -                      offset += file->f_pos;
 -              case SEEK_SET:
 -                      break;
 -              default:
 -                      goto out;
 -      }
 -      if (offset >= 0 && offset <= size) {
 -              if (offset != file->f_pos) {
 -                      file->f_pos = offset;
 -              }
 -              retval = offset;
 -      }
 -out:
 +      retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode));
        mutex_unlock(&bd_inode->i_mutex);
        return retval;
  }
@@@ -592,7 -606,7 +592,7 @@@ static struct block_device *bd_acquire(
        return bdev;
  }
  
static inline int sb_is_blkdev_sb(struct super_block *sb)
+ int sb_is_blkdev_sb(struct super_block *sb)
  {
        return sb == blockdev_superblock;
  }
@@@ -1519,7 -1533,7 +1519,7 @@@ ssize_t blkdev_aio_write(struct kiocb *
  
        blk_start_plug(&plug);
        ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
 -      if (ret > 0 || ret == -EIOCBQUEUED) {
 +      if (ret > 0) {
                ssize_t err;
  
                err = generic_write_sync(file, pos, ret);
@@@ -1542,7 -1556,7 +1542,7 @@@ static ssize_t blkdev_aio_read(struct k
                return 0;
  
        size -= pos;
 -      if (size < iocb->ki_left)
 +      if (size < iocb->ki_nbytes)
                nr_segs = iov_shorten((struct iovec *)iov, nr_segs, size);
        return generic_file_aio_read(iocb, iov, nr_segs, pos);
  }
@@@ -1569,7 -1583,6 +1569,7 @@@ static const struct address_space_opera
        .writepages     = generic_writepages,
        .releasepage    = blkdev_releasepage,
        .direct_IO      = blkdev_direct_IO,
 +      .is_dirty_writeback = buffer_check_dirty_writeback,
  };
  
  const struct file_operations def_blk_fops = {
diff --combined fs/fs-writeback.c
@@@ -45,7 -45,6 +45,7 @@@ struct wb_writeback_work 
        unsigned int for_kupdate:1;
        unsigned int range_cyclic:1;
        unsigned int for_background:1;
 +      unsigned int for_sync:1;        /* sync(2) WB_SYNC_ALL writeback */
        enum wb_reason reason;          /* why was writeback initiated? */
  
        struct list_head list;          /* pending work list */
@@@ -69,7 -68,7 +69,7 @@@ static inline struct backing_dev_info *
  {
        struct super_block *sb = inode->i_sb;
  
-       if (strcmp(sb->s_type->name, "bdev") == 0)
+       if (sb_is_blkdev_sb(sb))
                return inode->i_mapping->backing_dev_info;
  
        return sb->s_bdi;
@@@ -251,11 -250,13 +251,13 @@@ static int move_expired_inodes(struct l
                if (work->older_than_this &&
                    inode_dirtied_after(inode, *work->older_than_this))
                        break;
+               list_move(&inode->i_wb_list, &tmp);
+               moved++;
+               if (sb_is_blkdev_sb(inode->i_sb))
+                       continue;
                if (sb && sb != inode->i_sb)
                        do_sb_sort = 1;
                sb = inode->i_sb;
-               list_move(&inode->i_wb_list, &tmp);
-               moved++;
        }
  
        /* just one sb in list, splice to dispatch_queue and we're done */
@@@ -444,11 -445,9 +446,11 @@@ __writeback_single_inode(struct inode *
        /*
         * Make sure to wait on the data before writing out the metadata.
         * This is important for filesystems that modify metadata on data
 -       * I/O completion.
 +       * I/O completion. We don't do it for sync(2) writeback because it has a
 +       * separate, external IO completion path and ->sync_fs for guaranteeing
 +       * inode metadata is written back correctly.
         */
 -      if (wbc->sync_mode == WB_SYNC_ALL) {
 +      if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) {
                int err = filemap_fdatawait(mapping);
                if (ret == 0)
                        ret = err;
@@@ -581,7 -580,6 +583,7 @@@ static long writeback_sb_inodes(struct 
                .tagged_writepages      = work->tagged_writepages,
                .for_kupdate            = work->for_kupdate,
                .for_background         = work->for_background,
 +              .for_sync               = work->for_sync,
                .range_cyclic           = work->range_cyclic,
                .range_start            = 0,
                .range_end              = LLONG_MAX,
@@@ -723,7 -721,7 +725,7 @@@ static long __writeback_inodes_wb(struc
        return wrote;
  }
  
 -long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
 +static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
                                enum wb_reason reason)
  {
        struct wb_writeback_work work = {
@@@ -963,7 -961,7 +965,7 @@@ static long wb_check_old_data_flush(str
  /*
   * Retrieve work items and do the writeback they describe
   */
 -long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
 +static long wb_do_writeback(struct bdi_writeback *wb)
  {
        struct backing_dev_info *bdi = wb->bdi;
        struct wb_writeback_work *work;
  
        set_bit(BDI_writeback_running, &wb->bdi->state);
        while ((work = get_next_work_item(bdi)) != NULL) {
 -              /*
 -               * Override sync mode, in case we must wait for completion
 -               * because this thread is exiting now.
 -               */
 -              if (force_wait)
 -                      work->sync_mode = WB_SYNC_ALL;
  
                trace_writeback_exec(bdi, work);
  
@@@ -1019,7 -1023,7 +1021,7 @@@ void bdi_writeback_workfn(struct work_s
                 * rescuer as work_list needs to be drained.
                 */
                do {
 -                      pages_written = wb_do_writeback(wb, 0);
 +                      pages_written = wb_do_writeback(wb);
                        trace_writeback_pages_written(pages_written);
                } while (!list_empty(&bdi->work_list));
        } else {
@@@ -1049,8 -1053,10 +1051,8 @@@ void wakeup_flusher_threads(long nr_pag
  {
        struct backing_dev_info *bdi;
  
 -      if (!nr_pages) {
 -              nr_pages = global_page_state(NR_FILE_DIRTY) +
 -                              global_page_state(NR_UNSTABLE_NFS);
 -      }
 +      if (!nr_pages)
 +              nr_pages = get_nr_dirty_pages();
  
        rcu_read_lock();
        list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
@@@ -1171,8 -1177,6 +1173,8 @@@ void __mark_inode_dirty(struct inode *i
                        bool wakeup_bdi = false;
                        bdi = inode_to_bdi(inode);
  
 +                      spin_unlock(&inode->i_lock);
 +                      spin_lock(&bdi->wb.list_lock);
                        if (bdi_cap_writeback_dirty(bdi)) {
                                WARN(!test_bit(BDI_registered, &bdi->state),
                                     "bdi-%s not registered\n", bdi->name);
                                        wakeup_bdi = true;
                        }
  
 -                      spin_unlock(&inode->i_lock);
 -                      spin_lock(&bdi->wb.list_lock);
                        inode->dirtied_when = jiffies;
                        list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
                        spin_unlock(&bdi->wb.list_lock);
@@@ -1358,7 -1364,6 +1360,7 @@@ void sync_inodes_sb(struct super_block 
                .range_cyclic   = 0,
                .done           = &done,
                .reason         = WB_REASON_SYNC,
 +              .for_sync       = 1,
        };
  
        /* Nothing to do? */
diff --combined include/linux/fs.h
@@@ -10,8 -10,6 +10,8 @@@
  #include <linux/stat.h>
  #include <linux/cache.h>
  #include <linux/list.h>
 +#include <linux/list_lru.h>
 +#include <linux/llist.h>
  #include <linux/radix-tree.h>
  #include <linux/rbtree.h>
  #include <linux/init.h>
@@@ -47,7 -45,6 +47,7 @@@ struct vfsmount
  struct cred;
  struct swap_info_struct;
  struct seq_file;
 +struct workqueue_struct;
  
  extern void __init inode_init(void);
  extern void __init inode_init_early(void);
@@@ -65,7 -62,8 +65,7 @@@ struct buffer_head
  typedef int (get_block_t)(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create);
  typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 -                      ssize_t bytes, void *private, int ret,
 -                      bool is_async);
 +                      ssize_t bytes, void *private);
  
  #define MAY_EXEC              0x00000001
  #define MAY_WRITE             0x00000002
@@@ -366,7 -364,7 +366,7 @@@ struct address_space_operations 
  
        /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
        sector_t (*bmap)(struct address_space *, sector_t);
 -      void (*invalidatepage) (struct page *, unsigned long);
 +      void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, gfp_t);
        void (*freepage)(struct page *);
        ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
        int (*get_xip_mem)(struct address_space *, pgoff_t, int,
                                                void **, unsigned long *);
        /*
 -       * migrate the contents of a page to the specified target. If sync
 -       * is false, it must not block.
 +       * migrate the contents of a page to the specified target. If
 +       * migrate_mode is MIGRATE_ASYNC, it must not block.
         */
        int (*migratepage) (struct address_space *,
                        struct page *, struct page *, enum migrate_mode);
        int (*launder_page) (struct page *);
        int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
                                        unsigned long);
 +      void (*is_dirty_writeback) (struct page *, bool *, bool *);
        int (*error_remove_page)(struct address_space *, struct page *);
  
        /* swapfile support */
@@@ -770,7 -767,6 +770,7 @@@ struct file 
         */
        union {
                struct list_head        fu_list;
 +              struct llist_node       fu_llist;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
@@@ -912,7 -908,6 +912,7 @@@ struct file_lock_operations 
  
  struct lock_manager_operations {
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
 +      unsigned long (*lm_owner_key)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, struct file_lock *, int);
        void (*lm_break)(struct file_lock *);
@@@ -931,33 -926,14 +931,33 @@@ int locks_in_grace(struct net *)
  /* that will die - we need it for nfs_lock_info */
  #include <linux/nfs_fs_i.h>
  
 +/*
 + * struct file_lock represents a generic "file lock". It's used to represent
 + * POSIX byte range locks, BSD (flock) locks, and leases. It's important to
 + * note that the same struct is used to represent both a request for a lock and
 + * the lock itself, but the same object is never used for both.
 + *
 + * FIXME: should we create a separate "struct lock_request" to help distinguish
 + * these two uses?
 + *
 + * The i_flock list is ordered by:
 + *
 + * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX
 + * 2) lock owner
 + * 3) lock range start
 + * 4) lock range end
 + *
 + * Obviously, the last two criteria only matter for POSIX locks.
 + */
  struct file_lock {
        struct file_lock *fl_next;      /* singly linked list for this inode  */
 -      struct list_head fl_link;       /* doubly linked list of all locks */
 +      struct hlist_node fl_link;      /* node in global lists */
        struct list_head fl_block;      /* circular list of blocked processes */
        fl_owner_t fl_owner;
        unsigned int fl_flags;
        unsigned char fl_type;
        unsigned int fl_pid;
 +      int fl_link_cpu;                /* what cpu's list is this on? */
        struct pid *fl_nspid;
        wait_queue_head_t fl_wait;
        struct file *fl_file;
@@@ -1018,7 -994,7 +1018,7 @@@ extern void locks_release_private(struc
  extern void posix_test_lock(struct file *, struct file_lock *);
  extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
  extern int posix_lock_file_wait(struct file *, struct file_lock *);
 -extern int posix_unblock_lock(struct file *, struct file_lock *);
 +extern int posix_unblock_lock(struct file_lock *);
  extern int vfs_test_lock(struct file *, struct file_lock *);
  extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
  extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
@@@ -1030,6 -1006,9 +1030,6 @@@ extern int vfs_setlease(struct file *, 
  extern int lease_modify(struct file_lock **, int);
  extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
  extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
 -extern void locks_delete_block(struct file_lock *waiter);
 -extern void lock_flocks(void);
 -extern void unlock_flocks(void);
  #else /* !CONFIG_FILE_LOCKING */
  static inline int fcntl_getlk(struct file *file, struct flock __user *user)
  {
@@@ -1105,7 -1084,8 +1105,7 @@@ static inline int posix_lock_file_wait(
        return -ENOLCK;
  }
  
 -static inline int posix_unblock_lock(struct file *filp,
 -                                   struct file_lock *waiter)
 +static inline int posix_unblock_lock(struct file_lock *waiter)
  {
        return -ENOENT;
  }
@@@ -1170,6 -1150,19 +1170,6 @@@ static inline int lock_may_write(struc
  {
        return 1;
  }
 -
 -static inline void locks_delete_block(struct file_lock *waiter)
 -{
 -}
 -
 -static inline void lock_flocks(void)
 -{
 -}
 -
 -static inline void unlock_flocks(void)
 -{
 -}
 -
  #endif /* !CONFIG_FILE_LOCKING */
  
  
@@@ -1270,6 -1263,15 +1270,6 @@@ struct super_block 
        struct list_head        s_files;
  #endif
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
 -      /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */
 -      struct list_head        s_dentry_lru;   /* unused dentry lru */
 -      int                     s_nr_dentry_unused;     /* # of dentry on lru */
 -
 -      /* s_inode_lru_lock protects s_inode_lru and s_nr_inodes_unused */
 -      spinlock_t              s_inode_lru_lock ____cacheline_aligned_in_smp;
 -      struct list_head        s_inode_lru;            /* unused inode lru */
 -      int                     s_nr_inodes_unused;     /* # of inodes on lru */
 -
        struct block_device     *s_bdev;
        struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
  
        /* Being remounted read-only */
        int s_readonly_remount;
 -};
  
 -/* superblock cache pruning functions */
 -extern void prune_icache_sb(struct super_block *sb, int nr_to_scan);
 -extern void prune_dcache_sb(struct super_block *sb, int nr_to_scan);
 +      /* AIO completions deferred from interrupt context */
 +      struct workqueue_struct *s_dio_done_wq;
 +
 +      /*
 +       * Keep the lru lists last in the structure so they always sit on their
 +       * own individual cachelines.
 +       */
 +      struct list_lru         s_dentry_lru ____cacheline_aligned_in_smp;
 +      struct list_lru         s_inode_lru ____cacheline_aligned_in_smp;
 +};
  
  extern struct timespec current_fs_time(struct super_block *sb);
  
@@@ -1510,11 -1506,6 +1510,11 @@@ int fiemap_check_flags(struct fiemap_ex
   * to have different dirent layouts depending on the binary type.
   */
  typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
 +struct dir_context {
 +      const filldir_t actor;
 +      loff_t pos;
 +};
 +
  struct block_device_operations;
  
  /* These macros are for out of kernel modules to test that
@@@ -1530,7 -1521,7 +1530,7 @@@ struct file_operations 
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
 -      int (*readdir) (struct file *, void *, filldir_t);
 +      int (*iterate) (struct file *, struct dir_context *);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
@@@ -1584,7 -1575,6 +1584,7 @@@ struct inode_operations 
        int (*atomic_open)(struct inode *, struct dentry *,
                           struct file *, unsigned open_flag,
                           umode_t create_mode, int *opened);
 +      int (*tmpfile) (struct inode *, struct dentry *, umode_t);
  } ____cacheline_aligned;
  
  ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@@@ -1624,8 -1614,8 +1624,8 @@@ struct super_operations 
        ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
  #endif
        int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
 -      int (*nr_cached_objects)(struct super_block *);
 -      void (*free_cached_objects)(struct super_block *, int);
 +      long (*nr_cached_objects)(struct super_block *, int);
 +      long (*free_cached_objects)(struct super_block *, long, int);
  };
  
  /*
  #define I_REFERENCED          (1 << 8)
  #define __I_DIO_WAKEUP                9
  #define I_DIO_WAKEUP          (1 << I_DIO_WAKEUP)
 +#define I_LINKABLE            (1 << 10)
  
  #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
  
@@@ -1802,7 -1791,7 +1802,7 @@@ enum file_time_flags 
        S_VERSION = 8,
  };
  
 -extern void touch_atime(struct path *);
 +extern void touch_atime(const struct path *);
  static inline void file_accessed(struct file *file)
  {
        if (!(file->f_flags & O_NOATIME))
@@@ -1895,7 -1884,6 +1895,7 @@@ extern int vfs_ustat(dev_t, struct ksta
  extern int freeze_super(struct super_block *super);
  extern int thaw_super(struct super_block *super);
  extern bool our_mnt(struct vfsmount *mnt);
 +extern bool fs_fully_visible(struct file_system_type *);
  
  extern int current_umask(void);
  
  extern struct kobject *fs_kobj;
  
  #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
 -extern int rw_verify_area(int, struct file *, loff_t *, size_t);
  
  #define FLOCK_VERIFY_READ  1
  #define FLOCK_VERIFY_WRITE 2
@@@ -2069,6 -2058,7 +2069,7 @@@ extern struct super_block *freeze_bdev(
  extern void emergency_thaw_all(void);
  extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
  extern int fsync_bdev(struct block_device *);
+ extern int sb_is_blkdev_sb(struct super_block *sb);
  #else
  static inline void bd_forget(struct inode *inode) {}
  static inline int sync_blockdev(struct block_device *bdev) { return 0; }
@@@ -2088,6 -2078,11 +2089,11 @@@ static inline int thaw_bdev(struct bloc
  static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void *arg)
  {
  }
+ static inline int sb_is_blkdev_sb(struct super_block *sb)
+ {
+       return 0;
+ }
  #endif
  extern int sync_filesystem(struct super_block *);
  extern const struct file_operations def_blk_fops;
@@@ -2315,6 -2310,7 +2321,6 @@@ extern struct file * open_exec(const ch
  /* fs/dcache.c -- generic fs support functions */
  extern int is_subdir(struct dentry *, struct dentry *);
  extern int path_is_under(struct path *, struct path *);
 -extern ino_t find_inode_number(struct dentry *, struct qstr *);
  
  #include <linux/err.h>
  
@@@ -2429,12 -2425,9 +2435,12 @@@ extern voi
  file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
  extern loff_t noop_llseek(struct file *file, loff_t offset, int whence);
  extern loff_t no_llseek(struct file *file, loff_t offset, int whence);
 +extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize);
  extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
  extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
                int whence, loff_t maxsize, loff_t eof);
 +extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
 +              int whence, loff_t size);
  extern int generic_file_open(struct inode * inode, struct file * filp);
  extern int nonseekable_open(struct inode * inode, struct file * filp);
  
@@@ -2489,6 -2482,7 +2495,6 @@@ extern const struct file_operations gen
  #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
  
  extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
 -extern int vfs_follow_link(struct nameidata *, const char *);
  extern int page_readlink(struct dentry *, char __user *, int);
  extern void *page_follow_link_light(struct dentry *, struct nameidata *);
  extern void page_put_link(struct dentry *, struct nameidata *, void *);
@@@ -2501,13 -2495,11 +2507,13 @@@ extern void generic_fillattr(struct ino
  extern int vfs_getattr(struct path *, struct kstat *);
  void __inode_add_bytes(struct inode *inode, loff_t bytes);
  void inode_add_bytes(struct inode *inode, loff_t bytes);
 +void __inode_sub_bytes(struct inode *inode, loff_t bytes);
  void inode_sub_bytes(struct inode *inode, loff_t bytes);
  loff_t inode_get_bytes(struct inode *inode);
  void inode_set_bytes(struct inode *inode, loff_t bytes);
  
  extern int vfs_readdir(struct file *, filldir_t, void *);
 +extern int iterate_dir(struct file *, struct dir_context *);
  
  extern int vfs_stat(const char __user *, struct kstat *);
  extern int vfs_lstat(const char __user *, struct kstat *);
@@@ -2538,7 -2530,7 +2544,7 @@@ extern void iterate_supers_type(struct 
  extern int dcache_dir_open(struct inode *, struct file *);
  extern int dcache_dir_close(struct inode *, struct file *);
  extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 -extern int dcache_readdir(struct file *, void *, filldir_t);
 +extern int dcache_readdir(struct file *, struct dir_context *);
  extern int simple_setattr(struct dentry *, struct iattr *);
  extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
  extern int simple_statfs(struct dentry *, struct kstatfs *);
@@@ -2702,41 -2694,4 +2708,41 @@@ static inline void inode_has_no_xattr(s
                inode->i_flags |= S_NOSEC;
  }
  
 +static inline bool dir_emit(struct dir_context *ctx,
 +                          const char *name, int namelen,
 +                          u64 ino, unsigned type)
 +{
 +      return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0;
 +}
 +static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx)
 +{
 +      return ctx->actor(ctx, ".", 1, ctx->pos,
 +                        file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0;
 +}
 +static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
 +{
 +      return ctx->actor(ctx, "..", 2, ctx->pos,
 +                        parent_ino(file->f_path.dentry), DT_DIR) == 0;
 +}
 +static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
 +{
 +      if (ctx->pos == 0) {
 +              if (!dir_emit_dot(file, ctx))
 +                      return false;
 +              ctx->pos = 1;
 +      }
 +      if (ctx->pos == 1) {
 +              if (!dir_emit_dotdot(file, ctx))
 +                      return false;
 +              ctx->pos = 2;
 +      }
 +      return true;
 +}
 +static inline bool dir_relax(struct inode *inode)
 +{
 +      mutex_unlock(&inode->i_mutex);
 +      mutex_lock(&inode->i_mutex);
 +      return !IS_DEADDIR(inode);
 +}
 +
  #endif /* _LINUX_FS_H */