1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 1992, 1993, 1994, 1995
6 * Remy Card (card@masi.ibp.fr)
7 * Laboratoire MASI - Institut Blaise Pascal
8 * Universite Pierre et Marie Curie (Paris VI)
12 * linux/fs/minix/file.c
14 * Copyright (C) 1991, 1992 Linus Torvalds
16 * ext2 fs regular file handling primitives
18 * 64-bit file support on 64-bit platforms by Jakub Jelinek
19 * (jj@sunsite.ms.mff.cuni.cz)
22 #include <linux/time.h>
23 #include <linux/pagemap.h>
24 #include <linux/dax.h>
25 #include <linux/quotaops.h>
26 #include <linux/iomap.h>
27 #include <linux/uio.h>
28 #include <linux/buffer_head.h>
35 static ssize_t
ext2_dax_read_iter(struct kiocb
*iocb
, struct iov_iter
*to
)
37 struct inode
*inode
= iocb
->ki_filp
->f_mapping
->host
;
40 if (!iov_iter_count(to
))
41 return 0; /* skip atime */
43 inode_lock_shared(inode
);
44 ret
= dax_iomap_rw(iocb
, to
, &ext2_iomap_ops
);
45 inode_unlock_shared(inode
);
47 file_accessed(iocb
->ki_filp
);
51 static ssize_t
ext2_dax_write_iter(struct kiocb
*iocb
, struct iov_iter
*from
)
53 struct file
*file
= iocb
->ki_filp
;
54 struct inode
*inode
= file
->f_mapping
->host
;
58 ret
= generic_write_checks(iocb
, from
);
61 ret
= file_remove_privs(file
);
64 ret
= file_update_time(file
);
68 ret
= dax_iomap_rw(iocb
, from
, &ext2_iomap_ops
);
69 if (ret
> 0 && iocb
->ki_pos
> i_size_read(inode
)) {
70 i_size_write(inode
, iocb
->ki_pos
);
71 mark_inode_dirty(inode
);
77 ret
= generic_write_sync(iocb
, ret
);
82 * The lock ordering for ext2 DAX fault paths is:
85 * sb_start_pagefault (vfs, freeze)
86 * address_space->invalidate_lock
87 * address_space->i_mmap_rwsem or page_lock (mutually exclusive in DAX)
88 * ext2_inode_info->truncate_mutex
90 * The default page_lock and i_size verification done by non-DAX fault paths
91 * is sufficient because ext2 doesn't support hole punching.
93 static vm_fault_t
ext2_dax_fault(struct vm_fault
*vmf
)
95 struct inode
*inode
= file_inode(vmf
->vma
->vm_file
);
97 bool write
= (vmf
->flags
& FAULT_FLAG_WRITE
) &&
98 (vmf
->vma
->vm_flags
& VM_SHARED
);
101 sb_start_pagefault(inode
->i_sb
);
102 file_update_time(vmf
->vma
->vm_file
);
104 filemap_invalidate_lock_shared(inode
->i_mapping
);
106 ret
= dax_iomap_fault(vmf
, 0, NULL
, NULL
, &ext2_iomap_ops
);
108 filemap_invalidate_unlock_shared(inode
->i_mapping
);
110 sb_end_pagefault(inode
->i_sb
);
114 static const struct vm_operations_struct ext2_dax_vm_ops
= {
115 .fault
= ext2_dax_fault
,
117 * .huge_fault is not supported for DAX because allocation in ext2
118 * cannot be reliably aligned to huge page sizes and so pmd faults
119 * will always fail and fail back to regular faults.
121 .page_mkwrite
= ext2_dax_fault
,
122 .pfn_mkwrite
= ext2_dax_fault
,
125 static int ext2_file_mmap(struct file
*file
, struct vm_area_struct
*vma
)
127 if (!IS_DAX(file_inode(file
)))
128 return generic_file_mmap(file
, vma
);
131 vma
->vm_ops
= &ext2_dax_vm_ops
;
135 #define ext2_file_mmap generic_file_mmap
139 * Called when filp is released. This happens when all file descriptors
140 * for a single struct file are closed. Note that different open() calls
141 * for the same file yield different struct file structures.
143 static int ext2_release_file (struct inode
* inode
, struct file
* filp
)
145 if (filp
->f_mode
& FMODE_WRITE
) {
146 mutex_lock(&EXT2_I(inode
)->truncate_mutex
);
147 ext2_discard_reservation(inode
);
148 mutex_unlock(&EXT2_I(inode
)->truncate_mutex
);
153 int ext2_fsync(struct file
*file
, loff_t start
, loff_t end
, int datasync
)
156 struct super_block
*sb
= file
->f_mapping
->host
->i_sb
;
158 ret
= generic_buffers_fsync(file
, start
, end
, datasync
);
160 /* We don't really know where the IO error happened... */
161 ext2_error(sb
, __func__
,
162 "detected IO error when writing metadata buffers");
166 static ssize_t
ext2_dio_read_iter(struct kiocb
*iocb
, struct iov_iter
*to
)
168 struct file
*file
= iocb
->ki_filp
;
169 struct inode
*inode
= file
->f_mapping
->host
;
172 trace_ext2_dio_read_begin(iocb
, to
, 0);
173 inode_lock_shared(inode
);
174 ret
= iomap_dio_rw(iocb
, to
, &ext2_iomap_ops
, NULL
, 0, NULL
, 0);
175 inode_unlock_shared(inode
);
176 trace_ext2_dio_read_end(iocb
, to
, ret
);
181 static int ext2_dio_write_end_io(struct kiocb
*iocb
, ssize_t size
,
182 int error
, unsigned int flags
)
184 loff_t pos
= iocb
->ki_pos
;
185 struct inode
*inode
= file_inode(iocb
->ki_filp
);
191 * If we are extending the file, we have to update i_size here before
192 * page cache gets invalidated in iomap_dio_rw(). This prevents racing
193 * buffered reads from zeroing out too much from page cache pages.
194 * Note that all extending writes always happens synchronously with
195 * inode lock held by ext2_dio_write_iter(). So it is safe to update
196 * inode size here for extending file writes.
199 if (pos
> i_size_read(inode
)) {
200 i_size_write(inode
, pos
);
201 mark_inode_dirty(inode
);
204 trace_ext2_dio_write_endio(iocb
, size
, error
);
208 static const struct iomap_dio_ops ext2_dio_write_ops
= {
209 .end_io
= ext2_dio_write_end_io
,
212 static ssize_t
ext2_dio_write_iter(struct kiocb
*iocb
, struct iov_iter
*from
)
214 struct file
*file
= iocb
->ki_filp
;
215 struct inode
*inode
= file
->f_mapping
->host
;
217 unsigned int flags
= 0;
218 unsigned long blocksize
= inode
->i_sb
->s_blocksize
;
219 loff_t offset
= iocb
->ki_pos
;
220 loff_t count
= iov_iter_count(from
);
223 trace_ext2_dio_write_begin(iocb
, from
, 0);
225 ret
= generic_write_checks(iocb
, from
);
229 ret
= kiocb_modified(iocb
);
233 /* use IOMAP_DIO_FORCE_WAIT for unaligned or extending writes */
234 if (iocb
->ki_pos
+ iov_iter_count(from
) > i_size_read(inode
) ||
235 (!IS_ALIGNED(iocb
->ki_pos
| iov_iter_alignment(from
), blocksize
)))
236 flags
|= IOMAP_DIO_FORCE_WAIT
;
238 ret
= iomap_dio_rw(iocb
, from
, &ext2_iomap_ops
, &ext2_dio_write_ops
,
241 /* ENOTBLK is magic return value for fallback to buffered-io */
245 if (ret
< 0 && ret
!= -EIOCBQUEUED
)
246 ext2_write_failed(inode
->i_mapping
, offset
+ count
);
248 /* handle case for partial write and for fallback to buffered write */
249 if (ret
>= 0 && iov_iter_count(from
)) {
253 iocb
->ki_flags
&= ~IOCB_DIRECT
;
255 status
= generic_perform_write(iocb
, from
);
256 if (unlikely(status
< 0)) {
262 endbyte
= pos
+ status
- 1;
263 ret2
= filemap_write_and_wait_range(inode
->i_mapping
, pos
,
266 invalidate_mapping_pages(inode
->i_mapping
,
268 endbyte
>> PAGE_SHIFT
);
270 generic_write_sync(iocb
, ret
);
276 trace_ext2_dio_write_buff_end(iocb
, from
, status
);
277 trace_ext2_dio_write_end(iocb
, from
, ret
);
281 static ssize_t
ext2_file_read_iter(struct kiocb
*iocb
, struct iov_iter
*to
)
284 if (IS_DAX(iocb
->ki_filp
->f_mapping
->host
))
285 return ext2_dax_read_iter(iocb
, to
);
287 if (iocb
->ki_flags
& IOCB_DIRECT
)
288 return ext2_dio_read_iter(iocb
, to
);
290 return generic_file_read_iter(iocb
, to
);
293 static ssize_t
ext2_file_write_iter(struct kiocb
*iocb
, struct iov_iter
*from
)
296 if (IS_DAX(iocb
->ki_filp
->f_mapping
->host
))
297 return ext2_dax_write_iter(iocb
, from
);
299 if (iocb
->ki_flags
& IOCB_DIRECT
)
300 return ext2_dio_write_iter(iocb
, from
);
302 return generic_file_write_iter(iocb
, from
);
305 static int ext2_file_open(struct inode
*inode
, struct file
*filp
)
307 filp
->f_mode
|= FMODE_CAN_ODIRECT
;
308 return dquot_file_open(inode
, filp
);
311 const struct file_operations ext2_file_operations
= {
312 .llseek
= generic_file_llseek
,
313 .read_iter
= ext2_file_read_iter
,
314 .write_iter
= ext2_file_write_iter
,
315 .unlocked_ioctl
= ext2_ioctl
,
317 .compat_ioctl
= ext2_compat_ioctl
,
319 .mmap
= ext2_file_mmap
,
320 .open
= ext2_file_open
,
321 .release
= ext2_release_file
,
323 .get_unmapped_area
= thp_get_unmapped_area
,
324 .splice_read
= filemap_splice_read
,
325 .splice_write
= iter_file_splice_write
,
328 const struct inode_operations ext2_file_inode_operations
= {
329 .listxattr
= ext2_listxattr
,
330 .getattr
= ext2_getattr
,
331 .setattr
= ext2_setattr
,
332 .get_inode_acl
= ext2_get_acl
,
333 .set_acl
= ext2_set_acl
,
334 .fiemap
= ext2_fiemap
,
335 .fileattr_get
= ext2_fileattr_get
,
336 .fileattr_set
= ext2_fileattr_set
,