Merge tag 'asoc-v5.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6-block.git] / mm / filemap.c
index 6dd9a2274c805ad670959418f0caf27292c16bc4..d0cf700bf201c9ea73909788e7c379abde7eb0f4 100644 (file)
@@ -549,6 +549,28 @@ int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
 }
 EXPORT_SYMBOL(filemap_fdatawait_range);
 
+/**
+ * filemap_fdatawait_range_keep_errors - wait for writeback to complete
+ * @mapping:           address space structure to wait for
+ * @start_byte:                offset in bytes where the range starts
+ * @end_byte:          offset in bytes where the range ends (inclusive)
+ *
+ * Walk the list of under-writeback pages of the given address space in the
+ * given range and wait for all of them.  Unlike filemap_fdatawait_range(),
+ * this function does not clear error status of the address space.
+ *
+ * Use this function if callers don't handle errors themselves.  Expected
+ * call sites are system-wide / filesystem-wide data flushers: e.g. sync(2),
+ * fsfreeze(8)
+ */
+int filemap_fdatawait_range_keep_errors(struct address_space *mapping,
+               loff_t start_byte, loff_t end_byte)
+{
+       __filemap_fdatawait_range(mapping, start_byte, end_byte);
+       return filemap_check_and_keep_errors(mapping);
+}
+EXPORT_SYMBOL(filemap_fdatawait_range_keep_errors);
+
 /**
  * file_fdatawait_range - wait for writeback to complete
  * @file:              file pointing to address space structure to wait for
@@ -2482,10 +2504,8 @@ static struct file *do_async_mmap_readahead(struct vm_fault *vmf,
  *
  * vma->vm_mm->mmap_sem must be held on entry.
  *
- * If our return value has VM_FAULT_RETRY set, it's because
- * lock_page_or_retry() returned 0.
- * The mmap_sem has usually been released in this case.
- * See __lock_page_or_retry() for the exception.
+ * If our return value has VM_FAULT_RETRY set, it's because the mmap_sem
+ * may be dropped before doing I/O or by lock_page_maybe_drop_mmap().
  *
  * If our return value does not have VM_FAULT_RETRY set, the mmap_sem
  * has not been released.
@@ -2803,7 +2823,11 @@ repeat:
                }
 
 filler:
-               err = filler(data, page);
+               if (filler)
+                       err = filler(data, page);
+               else
+                       err = mapping->a_ops->readpage(data, page);
+
                if (err < 0) {
                        put_page(page);
                        return ERR_PTR(err);
@@ -2893,7 +2917,8 @@ struct page *read_cache_page(struct address_space *mapping,
                                int (*filler)(void *, struct page *),
                                void *data)
 {
-       return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping));
+       return do_read_cache_page(mapping, index, filler, data,
+                       mapping_gfp_mask(mapping));
 }
 EXPORT_SYMBOL(read_cache_page);
 
@@ -2914,9 +2939,7 @@ struct page *read_cache_page_gfp(struct address_space *mapping,
                                pgoff_t index,
                                gfp_t gfp)
 {
-       filler_t *filler = (filler_t *)mapping->a_ops->readpage;
-
-       return do_read_cache_page(mapping, index, filler, NULL, gfp);
+       return do_read_cache_page(mapping, index, NULL, NULL, gfp);
 }
 EXPORT_SYMBOL(read_cache_page_gfp);
 
@@ -2925,24 +2948,11 @@ EXPORT_SYMBOL(read_cache_page_gfp);
  * LFS limits.  If pos is under the limit it becomes a short access.  If it
  * exceeds the limit we return -EFBIG.
  */
-static int generic_access_check_limits(struct file *file, loff_t pos,
-                                      loff_t *count)
-{
-       struct inode *inode = file->f_mapping->host;
-       loff_t max_size = inode->i_sb->s_maxbytes;
-
-       if (!(file->f_flags & O_LARGEFILE))
-               max_size = MAX_NON_LFS;
-
-       if (unlikely(pos >= max_size))
-               return -EFBIG;
-       *count = min(*count, max_size - pos);
-       return 0;
-}
-
 static int generic_write_check_limits(struct file *file, loff_t pos,
                                      loff_t *count)
 {
+       struct inode *inode = file->f_mapping->host;
+       loff_t max_size = inode->i_sb->s_maxbytes;
        loff_t limit = rlimit(RLIMIT_FSIZE);
 
        if (limit != RLIM_INFINITY) {
@@ -2953,7 +2963,15 @@ static int generic_write_check_limits(struct file *file, loff_t pos,
                *count = min(*count, limit - pos);
        }
 
-       return generic_access_check_limits(file, pos, count);
+       if (!(file->f_flags & O_LARGEFILE))
+               max_size = MAX_NON_LFS;
+
+       if (unlikely(pos >= max_size))
+               return -EFBIG;
+
+       *count = min(*count, max_size - pos);
+
+       return 0;
 }
 
 /*
@@ -2993,7 +3011,7 @@ EXPORT_SYMBOL(generic_write_checks);
 /*
  * Performs necessary checks before doing a clone.
  *
- * Can adjust amount of bytes to clone.
+ * Can adjust amount of bytes to clone via @req_count argument.
  * Returns appropriate error code that caller should return or
  * zero in case the clone should be allowed.
  */
@@ -3031,10 +3049,6 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
                return -EINVAL;
        count = min(count, size_in - (uint64_t)pos_in);
 
-       ret = generic_access_check_limits(file_in, pos_in, &count);
-       if (ret)
-               return ret;
-
        ret = generic_write_check_limits(file_out, pos_out, &count);
        if (ret)
                return ret;
@@ -3071,6 +3085,83 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
        return 0;
 }
 
+
+/*
+ * Performs common checks before doing a file copy/clone
+ * from @file_in to @file_out.
+ */
+int generic_file_rw_checks(struct file *file_in, struct file *file_out)
+{
+       struct inode *inode_in = file_inode(file_in);
+       struct inode *inode_out = file_inode(file_out);
+
+       /* Don't copy dirs, pipes, sockets... */
+       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
+               return -EISDIR;
+       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
+               return -EINVAL;
+
+       if (!(file_in->f_mode & FMODE_READ) ||
+           !(file_out->f_mode & FMODE_WRITE) ||
+           (file_out->f_flags & O_APPEND))
+               return -EBADF;
+
+       return 0;
+}
+
+/*
+ * Performs necessary checks before doing a file copy
+ *
+ * Can adjust amount of bytes to copy via @req_count argument.
+ * Returns appropriate error code that caller should return or
+ * zero in case the copy should be allowed.
+ */
+int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
+                            struct file *file_out, loff_t pos_out,
+                            size_t *req_count, unsigned int flags)
+{
+       struct inode *inode_in = file_inode(file_in);
+       struct inode *inode_out = file_inode(file_out);
+       uint64_t count = *req_count;
+       loff_t size_in;
+       int ret;
+
+       ret = generic_file_rw_checks(file_in, file_out);
+       if (ret)
+               return ret;
+
+       /* Don't touch certain kinds of inodes */
+       if (IS_IMMUTABLE(inode_out))
+               return -EPERM;
+
+       if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
+               return -ETXTBSY;
+
+       /* Ensure offsets don't wrap. */
+       if (pos_in + count < pos_in || pos_out + count < pos_out)
+               return -EOVERFLOW;
+
+       /* Shorten the copy to EOF */
+       size_in = i_size_read(inode_in);
+       if (pos_in >= size_in)
+               count = 0;
+       else
+               count = min(count, size_in - (uint64_t)pos_in);
+
+       ret = generic_write_check_limits(file_out, pos_out, &count);
+       if (ret)
+               return ret;
+
+       /* Don't allow overlapped copying within the same file. */
+       if (inode_in == inode_out &&
+           pos_out + count > pos_in &&
+           pos_out < pos_in + count)
+               return -EINVAL;
+
+       *req_count = count;
+       return 0;
+}
+
 int pagecache_write_begin(struct file *file, struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
                                struct page **pagep, void **fsdata)