]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - fs/inode.c
quota: add missing use of dq_data_lock in __dquot_initialize
[linux-3.10.git] / fs / inode.c
index ecbb68dc7e2aef9bbf52d0b94c0dd401a7d50bae..f5f7c06c36fb159f89a793510c62f3f9170c3e4d 100644 (file)
@@ -2,30 +2,21 @@
  * (C) 1997 Linus Torvalds
  * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
  */
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/dcache.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/writeback.h>
-#include <linux/module.h>
 #include <linux/backing-dev.h>
-#include <linux/wait.h>
-#include <linux/rwsem.h>
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
-#include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
 #include <linux/fsnotify.h>
 #include <linux/mount.h>
-#include <linux/async.h>
 #include <linux/posix_acl.h>
 #include <linux/prefetch.h>
-#include <linux/ima.h>
-#include <linux/cred.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
+#include <linux/ratelimit.h>
 #include "internal.h"
 
 /*
@@ -142,10 +133,10 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        atomic_set(&inode->i_count, 1);
        inode->i_op = &empty_iops;
        inode->i_fop = &empty_fops;
-       inode->i_nlink = 1;
+       inode->__i_nlink = 1;
        inode->i_opflags = 0;
-       inode->i_uid = 0;
-       inode->i_gid = 0;
+       i_uid_write(inode, 0);
+       i_gid_write(inode, 0);
        atomic_set(&inode->i_writecount, 0);
        inode->i_size = 0;
        inode->i_blocks = 0;
@@ -174,7 +165,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        mapping->host = inode;
        mapping->flags = 0;
        mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE);
-       mapping->assoc_mapping = NULL;
+       mapping->private_data = NULL;
        mapping->backing_dev_info = &default_backing_dev_info;
        mapping->writeback_index = 0;
 
@@ -191,6 +182,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        }
        inode->i_private = NULL;
        inode->i_mapping = mapping;
+       INIT_HLIST_HEAD(&inode->i_dentry);      /* buggered by rcu freeing */
 #ifdef CONFIG_FS_POSIX_ACL
        inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
 #endif
@@ -241,6 +233,11 @@ void __destroy_inode(struct inode *inode)
        BUG_ON(inode_has_buffers(inode));
        security_inode_free(inode);
        fsnotify_inode_delete(inode);
+       if (!inode->i_nlink) {
+               WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
+               atomic_long_dec(&inode->i_sb->s_remove_count);
+       }
+
 #ifdef CONFIG_FS_POSIX_ACL
        if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
                posix_acl_release(inode->i_acl);
@@ -254,7 +251,6 @@ EXPORT_SYMBOL(__destroy_inode);
 static void i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
-       INIT_LIST_HEAD(&inode->i_dentry);
        kmem_cache_free(inode_cachep, inode);
 }
 
@@ -268,6 +264,82 @@ static void destroy_inode(struct inode *inode)
                call_rcu(&inode->i_rcu, i_callback);
 }
 
+/**
+ * drop_nlink - directly drop an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  In cases
+ * where we are attempting to track writes to the
+ * filesystem, a decrement to zero means an imminent
+ * write when the file is truncated and actually unlinked
+ * on the filesystem.
+ */
+void drop_nlink(struct inode *inode)
+{
+       WARN_ON(inode->i_nlink == 0);
+       inode->__i_nlink--;
+       if (!inode->i_nlink)
+               atomic_long_inc(&inode->i_sb->s_remove_count);
+}
+EXPORT_SYMBOL(drop_nlink);
+
+/**
+ * clear_nlink - directly zero an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  See
+ * drop_nlink() for why we care about i_nlink hitting zero.
+ */
+void clear_nlink(struct inode *inode)
+{
+       if (inode->i_nlink) {
+               inode->__i_nlink = 0;
+               atomic_long_inc(&inode->i_sb->s_remove_count);
+       }
+}
+EXPORT_SYMBOL(clear_nlink);
+
+/**
+ * set_nlink - directly set an inode's link count
+ * @inode: inode
+ * @nlink: new nlink (should be non-zero)
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.
+ */
+void set_nlink(struct inode *inode, unsigned int nlink)
+{
+       if (!nlink) {
+               clear_nlink(inode);
+       } else {
+               /* Yes, some filesystems do change nlink from zero to one */
+               if (inode->i_nlink == 0)
+                       atomic_long_dec(&inode->i_sb->s_remove_count);
+
+               inode->__i_nlink = nlink;
+       }
+}
+EXPORT_SYMBOL(set_nlink);
+
+/**
+ * inc_nlink - directly increment an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  Currently,
+ * it is only here for parity with dec_nlink().
+ */
+void inc_nlink(struct inode *inode)
+{
+       if (WARN_ON(inode->i_nlink == 0))
+               atomic_long_dec(&inode->i_sb->s_remove_count);
+
+       inode->__i_nlink++;
+}
+EXPORT_SYMBOL(inc_nlink);
+
 void address_space_init_once(struct address_space *mapping)
 {
        memset(mapping, 0, sizeof(*mapping));
@@ -276,7 +348,7 @@ void address_space_init_once(struct address_space *mapping)
        mutex_init(&mapping->i_mmap_mutex);
        INIT_LIST_HEAD(&mapping->private_list);
        spin_lock_init(&mapping->private_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
+       mapping->i_mmap = RB_ROOT;
        INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
 }
 EXPORT_SYMBOL(address_space_init_once);
@@ -290,7 +362,6 @@ void inode_init_once(struct inode *inode)
 {
        memset(inode, 0, sizeof(*inode));
        INIT_HLIST_NODE(&inode->i_hash);
-       INIT_LIST_HEAD(&inode->i_dentry);
        INIT_LIST_HEAD(&inode->i_devices);
        INIT_LIST_HEAD(&inode->i_wb_list);
        INIT_LIST_HEAD(&inode->i_lru);
@@ -337,6 +408,19 @@ static void inode_lru_list_add(struct inode *inode)
        spin_unlock(&inode->i_sb->s_inode_lru_lock);
 }
 
+/*
+ * Add inode to LRU if needed (inode is unused and clean).
+ *
+ * Needs inode->i_lock held.
+ */
+void inode_add_lru(struct inode *inode)
+{
+       if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) &&
+           !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE)
+               inode_lru_list_add(inode);
+}
+
+
 static void inode_lru_list_del(struct inode *inode)
 {
        spin_lock(&inode->i_sb->s_inode_lru_lock);
@@ -415,7 +499,7 @@ void __remove_inode_hash(struct inode *inode)
 }
 EXPORT_SYMBOL(__remove_inode_hash);
 
-void end_writeback(struct inode *inode)
+void clear_inode(struct inode *inode)
 {
        might_sleep();
        /*
@@ -429,11 +513,10 @@ void end_writeback(struct inode *inode)
        BUG_ON(!list_empty(&inode->i_data.private_list));
        BUG_ON(!(inode->i_state & I_FREEING));
        BUG_ON(inode->i_state & I_CLEAR);
-       inode_sync_wait(inode);
        /* don't need i_lock here, no concurrent mods to i_state */
        inode->i_state = I_FREEING | I_CLEAR;
 }
-EXPORT_SYMBOL(end_writeback);
+EXPORT_SYMBOL(clear_inode);
 
 /*
  * Free the inode passed in, removing it from the lists it is still connected
@@ -460,12 +543,20 @@ static void evict(struct inode *inode)
 
        inode_sb_list_del(inode);
 
+       /*
+        * Wait for flusher thread to be done with the inode so that filesystem
+        * does not start destroying it while writeback is still running. Since
+        * the inode has I_FREEING set, flusher thread won't start new work on
+        * the inode.  We just have to wait for running writeback to finish.
+        */
+       inode_wait_for_writeback(inode);
+
        if (op->evict_inode) {
                op->evict_inode(inode);
        } else {
                if (inode->i_data.nrpages)
                        truncate_inode_pages(&inode->i_data, 0);
-               end_writeback(inode);
+               clear_inode(inode);
        }
        if (S_ISBLK(inode->i_mode) && inode->i_bdev)
                bd_forget(inode);
@@ -692,6 +783,8 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan)
        else
                __count_vm_events(PGINODESTEAL, reap);
        spin_unlock(&sb->s_inode_lru_lock);
+       if (current->reclaim_state)
+               current->reclaim_state->reclaimed_slab += reap;
 
        dispose_list(&freeable);
 }
@@ -705,11 +798,10 @@ static struct inode *find_inode(struct super_block *sb,
                                int (*test)(struct inode *, void *),
                                void *data)
 {
-       struct hlist_node *node;
        struct inode *inode = NULL;
 
 repeat:
-       hlist_for_each_entry(inode, node, head, i_hash) {
+       hlist_for_each_entry(inode, head, i_hash) {
                spin_lock(&inode->i_lock);
                if (inode->i_sb != sb) {
                        spin_unlock(&inode->i_lock);
@@ -737,11 +829,10 @@ repeat:
 static struct inode *find_inode_fast(struct super_block *sb,
                                struct hlist_head *head, unsigned long ino)
 {
-       struct hlist_node *node;
        struct inode *inode = NULL;
 
 repeat:
-       hlist_for_each_entry(inode, node, head, i_hash) {
+       hlist_for_each_entry(inode, head, i_hash) {
                spin_lock(&inode->i_lock);
                if (inode->i_ino != ino) {
                        spin_unlock(&inode->i_lock);
@@ -855,8 +946,7 @@ void lockdep_annotate_inode_mutex_key(struct inode *inode)
                struct file_system_type *type = inode->i_sb->s_type;
 
                /* Set new key only if filesystem hasn't already changed it */
-               if (!lockdep_match_class(&inode->i_mutex,
-                   &type->i_mutex_key)) {
+               if (lockdep_match_class(&inode->i_mutex, &type->i_mutex_key)) {
                        /*
                         * ensure nobody is actually holding i_mutex
                         */
@@ -883,6 +973,7 @@ void unlock_new_inode(struct inode *inode)
        spin_lock(&inode->i_lock);
        WARN_ON(!(inode->i_state & I_NEW));
        inode->i_state &= ~I_NEW;
+       smp_mb();
        wake_up_bit(&inode->i_state, __I_NEW);
        spin_unlock(&inode->i_lock);
 }
@@ -1039,11 +1130,10 @@ EXPORT_SYMBOL(iget_locked);
 static int test_inode_iunique(struct super_block *sb, unsigned long ino)
 {
        struct hlist_head *b = inode_hashtable + hash(sb, ino);
-       struct hlist_node *node;
        struct inode *inode;
 
        spin_lock(&inode_hash_lock);
-       hlist_for_each_entry(inode, node, b, i_hash) {
+       hlist_for_each_entry(inode, b, i_hash) {
                if (inode->i_ino == ino && inode->i_sb == sb) {
                        spin_unlock(&inode_hash_lock);
                        return 0;
@@ -1198,10 +1288,9 @@ int insert_inode_locked(struct inode *inode)
        struct hlist_head *head = inode_hashtable + hash(sb, ino);
 
        while (1) {
-               struct hlist_node *node;
                struct inode *old = NULL;
                spin_lock(&inode_hash_lock);
-               hlist_for_each_entry(old, node, head, i_hash) {
+               hlist_for_each_entry(old, head, i_hash) {
                        if (old->i_ino != ino)
                                continue;
                        if (old->i_sb != sb)
@@ -1213,7 +1302,7 @@ int insert_inode_locked(struct inode *inode)
                        }
                        break;
                }
-               if (likely(!node)) {
+               if (likely(!old)) {
                        spin_lock(&inode->i_lock);
                        inode->i_state |= I_NEW;
                        hlist_add_head(&inode->i_hash, head);
@@ -1241,11 +1330,10 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
        struct hlist_head *head = inode_hashtable + hash(sb, hashval);
 
        while (1) {
-               struct hlist_node *node;
                struct inode *old = NULL;
 
                spin_lock(&inode_hash_lock);
-               hlist_for_each_entry(old, node, head, i_hash) {
+               hlist_for_each_entry(old, head, i_hash) {
                        if (old->i_sb != sb)
                                continue;
                        if (!test(old, data))
@@ -1257,7 +1345,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
                        }
                        break;
                }
-               if (likely(!node)) {
+               if (likely(!old)) {
                        spin_lock(&inode->i_lock);
                        inode->i_state |= I_NEW;
                        hlist_add_head(&inode->i_hash, head);
@@ -1285,17 +1373,6 @@ int generic_delete_inode(struct inode *inode)
 }
 EXPORT_SYMBOL(generic_delete_inode);
 
-/*
- * Normal UNIX filesystem behaviour: delete the
- * inode when the usage count drops to zero, and
- * i_nlink is zero.
- */
-int generic_drop_inode(struct inode *inode)
-{
-       return !inode->i_nlink || inode_unhashed(inode);
-}
-EXPORT_SYMBOL_GPL(generic_drop_inode);
-
 /*
  * Called when we're dropping the last reference
  * to an inode.
@@ -1321,8 +1398,7 @@ static void iput_final(struct inode *inode)
 
        if (!drop && (sb->s_flags & MS_ACTIVE)) {
                inode->i_state |= I_REFERENCED;
-               if (!(inode->i_state & (I_DIRTY|I_SYNC)))
-                       inode_lru_list_add(inode);
+               inode_add_lru(inode);
                spin_unlock(&inode->i_lock);
                return;
        }
@@ -1418,18 +1494,39 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
        return 0;
 }
 
+/*
+ * This does the actual work of updating an inodes time or version.  Must have
+ * had called mnt_want_write() before calling this.
+ */
+static int update_time(struct inode *inode, struct timespec *time, int flags)
+{
+       if (inode->i_op->update_time)
+               return inode->i_op->update_time(inode, time, flags);
+
+       if (flags & S_ATIME)
+               inode->i_atime = *time;
+       if (flags & S_VERSION)
+               inode_inc_iversion(inode);
+       if (flags & S_CTIME)
+               inode->i_ctime = *time;
+       if (flags & S_MTIME)
+               inode->i_mtime = *time;
+       mark_inode_dirty_sync(inode);
+       return 0;
+}
+
 /**
  *     touch_atime     -       update the access time
- *     @mnt: mount the inode is accessed on
- *     @dentry: dentry accessed
+ *     @path: the &struct path to update
  *
  *     Update the accessed time on an inode and mark it for writeback.
  *     This function automatically handles read only file systems and media,
  *     as well as the "noatime" flag and inode specific "noatime" markers.
  */
-void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
+void touch_atime(struct path *path)
 {
-       struct inode *inode = dentry->d_inode;
+       struct vfsmount *mnt = path->mnt;
+       struct inode *inode = path->dentry->d_inode;
        struct timespec now;
 
        if (inode->i_flags & S_NOATIME)
@@ -1452,15 +1549,92 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
        if (timespec_equal(&inode->i_atime, &now))
                return;
 
-       if (mnt_want_write(mnt))
+       if (!sb_start_write_trylock(inode->i_sb))
                return;
 
-       inode->i_atime = now;
-       mark_inode_dirty_sync(inode);
-       mnt_drop_write(mnt);
+       if (__mnt_want_write(mnt))
+               goto skip_update;
+       /*
+        * File systems can error out when updating inodes if they need to
+        * allocate new space to modify an inode (such is the case for
+        * Btrfs), but since we touch atime while walking down the path we
+        * really don't care if we failed to update the atime of the file,
+        * so just ignore the return value.
+        * We may also fail on filesystems that have the ability to make parts
+        * of the fs read only, e.g. subvolumes in Btrfs.
+        */
+       update_time(inode, &now, S_ATIME);
+       __mnt_drop_write(mnt);
+skip_update:
+       sb_end_write(inode->i_sb);
 }
 EXPORT_SYMBOL(touch_atime);
 
+/*
+ * The logic we want is
+ *
+ *     if suid or (sgid and xgrp)
+ *             remove privs
+ */
+int should_remove_suid(struct dentry *dentry)
+{
+       umode_t mode = dentry->d_inode->i_mode;
+       int kill = 0;
+
+       /* suid always must be killed */
+       if (unlikely(mode & S_ISUID))
+               kill = ATTR_KILL_SUID;
+
+       /*
+        * sgid without any exec bits is just a mandatory locking mark; leave
+        * it alone.  If some exec bits are set, it's a real sgid; kill it.
+        */
+       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+               kill |= ATTR_KILL_SGID;
+
+       if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
+               return kill;
+
+       return 0;
+}
+EXPORT_SYMBOL(should_remove_suid);
+
+static int __remove_suid(struct dentry *dentry, int kill)
+{
+       struct iattr newattrs;
+
+       newattrs.ia_valid = ATTR_FORCE | kill;
+       return notify_change(dentry, &newattrs);
+}
+
+int file_remove_suid(struct file *file)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       int killsuid;
+       int killpriv;
+       int error = 0;
+
+       /* Fast path for nothing security related */
+       if (IS_NOSEC(inode))
+               return 0;
+
+       killsuid = should_remove_suid(dentry);
+       killpriv = security_inode_need_killpriv(dentry);
+
+       if (killpriv < 0)
+               return killpriv;
+       if (killpriv)
+               error = security_inode_killpriv(dentry);
+       if (!error && killsuid)
+               error = __remove_suid(dentry, killsuid);
+       if (!error && (inode->i_sb->s_flags & MS_NOSEC))
+               inode->i_flags |= S_NOSEC;
+
+       return error;
+}
+EXPORT_SYMBOL(file_remove_suid);
+
 /**
  *     file_update_time        -       update mtime and ctime time
  *     @file: file accessed
@@ -1470,18 +1644,20 @@ EXPORT_SYMBOL(touch_atime);
  *     usage in the file write path of filesystems, and filesystems may
  *     choose to explicitly ignore update via this function with the
  *     S_NOCMTIME inode flag, e.g. for network filesystem where these
- *     timestamps are handled by the server.
+ *     timestamps are handled by the server.  This can return an error for
+ *     file systems who need to allocate space in order to update an inode.
  */
 
-void file_update_time(struct file *file)
+int file_update_time(struct file *file)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct timespec now;
-       enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0;
+       int sync_it = 0;
+       int ret;
 
        /* First try to exhaust all avenues to not sync */
        if (IS_NOCMTIME(inode))
-               return;
+               return 0;
 
        now = current_fs_time(inode->i_sb);
        if (!timespec_equal(&inode->i_mtime, &now))
@@ -1494,21 +1670,16 @@ void file_update_time(struct file *file)
                sync_it |= S_VERSION;
 
        if (!sync_it)
-               return;
+               return 0;
 
        /* Finally allowed to write? Takes lock. */
-       if (mnt_want_write_file(file))
-               return;
+       if (__mnt_want_write_file(file))
+               return 0;
 
-       /* Only change inode inside the lock region */
-       if (sync_it & S_VERSION)
-               inode_inc_iversion(inode);
-       if (sync_it & S_CTIME)
-               inode->i_ctime = now;
-       if (sync_it & S_MTIME)
-               inode->i_mtime = now;
-       mark_inode_dirty_sync(inode);
-       mnt_drop_write(file->f_path.mnt);
+       ret = update_time(inode, &now, sync_it);
+       __mnt_drop_write_file(file);
+
+       return ret;
 }
 EXPORT_SYMBOL(file_update_time);
 
@@ -1568,7 +1739,7 @@ __setup("ihash_entries=", set_ihash_entries);
  */
 void __init inode_init_early(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* If hashes are distributed across NUMA nodes, defer
         * hash allocation until vmalloc space is available.
@@ -1584,15 +1755,16 @@ void __init inode_init_early(void)
                                        HASH_EARLY,
                                        &i_hash_shift,
                                        &i_hash_mask,
+                                       0,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
 void __init inode_init(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* inode slab cache */
        inode_cachep = kmem_cache_create("inode_cache",
@@ -1614,9 +1786,10 @@ void __init inode_init(void)
                                        0,
                                        &i_hash_shift,
                                        &i_hash_mask,
+                                       0,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
@@ -1647,7 +1820,7 @@ EXPORT_SYMBOL(init_special_inode);
  * @mode: mode of the new inode
  */
 void inode_init_owner(struct inode *inode, const struct inode *dir,
-                       mode_t mode)
+                       umode_t mode)
 {
        inode->i_uid = current_fsuid();
        if (dir && dir->i_mode & S_ISGID) {
@@ -1669,12 +1842,57 @@ EXPORT_SYMBOL(inode_init_owner);
  */
 bool inode_owner_or_capable(const struct inode *inode)
 {
-       struct user_namespace *ns = inode_userns(inode);
-
-       if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
+       if (uid_eq(current_fsuid(), inode->i_uid))
                return true;
-       if (ns_capable(ns, CAP_FOWNER))
+       if (inode_capable(inode, CAP_FOWNER))
                return true;
        return false;
 }
 EXPORT_SYMBOL(inode_owner_or_capable);
+
+/*
+ * Direct i/o helper functions
+ */
+static void __inode_dio_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP);
+       DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP);
+
+       do {
+               prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&inode->i_dio_count))
+                       schedule();
+       } while (atomic_read(&inode->i_dio_count));
+       finish_wait(wq, &q.wait);
+}
+
+/**
+ * inode_dio_wait - wait for outstanding DIO requests to finish
+ * @inode: inode to wait for
+ *
+ * Waits for all pending direct I/O requests to finish so that we can
+ * proceed with a truncate or equivalent operation.
+ *
+ * Must be called under a lock that serializes taking new references
+ * to i_dio_count, usually by inode->i_mutex.
+ */
+void inode_dio_wait(struct inode *inode)
+{
+       if (atomic_read(&inode->i_dio_count))
+               __inode_dio_wait(inode);
+}
+EXPORT_SYMBOL(inode_dio_wait);
+
+/*
+ * inode_dio_done - signal finish of a direct I/O requests
+ * @inode: inode the direct I/O happens on
+ *
+ * This is called once we've finished processing a direct I/O request,
+ * and is used to wake up callers waiting for direct I/O to be quiesced.
+ */
+void inode_dio_done(struct inode *inode)
+{
+       if (atomic_dec_and_test(&inode->i_dio_count))
+               wake_up_bit(&inode->i_state, __I_DIO_WAKEUP);
+}
+EXPORT_SYMBOL(inode_dio_done);