flags, ac);
}
+/*
+ * We need to lock the test/set EOF update as we can be racing with
+ * other IO completions here to update the EOF. Failing to serialise
+ * here can result in EOF moving backwards and Bad Things Happen when
+ * that occurs.
+ *
+ * As IO completion only ever extends EOF, we can do an unlocked check
+ * here to avoid taking the spinlock. If we land within the current EOF,
+ * then we do not need to do an extending update at all, and we don't
+ * need to take the lock to check this. If we race with an update moving
+ * EOF, then we'll either still be beyond EOF and need to take the lock,
+ * or we'll be within EOF and we don't need to take it at all.
+ */
+static int
+xfs_dio_endio_set_isize(
+ struct inode *inode,
+ loff_t offset,
+ ssize_t size)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+
+ if (offset + size <= i_size_read(inode))
+ return 0;
+
+ spin_lock(&ip->i_flags_lock);
+ if (offset + size <= i_size_read(inode)) {
+ spin_unlock(&ip->i_flags_lock);
+ return 0;
+ }
+
+ i_size_write(inode, offset + size);
+ spin_unlock(&ip->i_flags_lock);
+
+ return xfs_setfilesize(ip, offset, size);
+}
+
static int
xfs_dio_write_end_io(
struct kiocb *iocb,
* with the on-disk inode size being outside the in-core inode size. We
* have no other method of updating EOF for AIO, so always do it here
* if necessary.
- *
- * We need to lock the test/set EOF update as we can be racing with
- * other IO completions here to update the EOF. Failing to serialise
- * here can result in EOF moving backwards and Bad Things Happen when
- * that occurs.
- *
- * As IO completion only ever extends EOF, we can do an unlocked check
- * here to avoid taking the spinlock. If we land within the current EOF,
- * then we do not need to do an extending update at all, and we don't
- * need to take the lock to check this. If we race with an update moving
- * EOF, then we'll either still be beyond EOF and need to take the lock,
- * or we'll be within EOF and we don't need to take it at all.
*/
- if (offset + size <= i_size_read(inode))
- goto out;
-
- spin_lock(&ip->i_flags_lock);
- if (offset + size > i_size_read(inode)) {
- i_size_write(inode, offset + size);
- spin_unlock(&ip->i_flags_lock);
- error = xfs_setfilesize(ip, offset, size);
- } else {
- spin_unlock(&ip->i_flags_lock);
- }
+ error = xfs_dio_endio_set_isize(inode, offset, size);
out:
memalloc_nofs_restore(nofs_flag);