Blame view
fs/ext2/file.c
4.86 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* * linux/fs/ext2/file.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/file.c * * Copyright (C) 1991, 1992 Linus Torvalds * * ext2 fs regular file handling primitives * * 64-bit file support on 64-bit platforms by Jakub Jelinek * (jj@sunsite.ms.mff.cuni.cz) */ #include <linux/time.h> |
48bde86df
|
22 |
#include <linux/pagemap.h> |
c94c2acf8
|
23 |
#include <linux/dax.h> |
871a29315
|
24 |
#include <linux/quotaops.h> |
1da177e4c
|
25 26 27 |
#include "ext2.h" #include "xattr.h" #include "acl.h" |
6cd176a51
|
28 |
#ifdef CONFIG_FS_DAX |
5726b27b0
|
29 30 31 32 33 34 35 36 37 38 39 40 |
/* * The lock ordering for ext2 DAX fault paths is: * * mmap_sem (MM) * sb_start_pagefault (vfs, freeze) * ext2_inode_info->dax_sem * address_space->i_mmap_rwsem or page_lock (mutually exclusive in DAX) * ext2_inode_info->truncate_mutex * * The default page_lock and i_size verification done by non-DAX fault paths * is sufficient because ext2 doesn't support hole punching. */ |
f7ca90b16
|
41 42 |
static int ext2_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { |
5726b27b0
|
43 44 45 46 47 48 49 50 51 |
struct inode *inode = file_inode(vma->vm_file); struct ext2_inode_info *ei = EXT2_I(inode); int ret; if (vmf->flags & FAULT_FLAG_WRITE) { sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); } down_read(&ei->dax_sem); |
02fbd1397
|
52 |
ret = __dax_fault(vma, vmf, ext2_get_block); |
5726b27b0
|
53 54 55 56 57 |
up_read(&ei->dax_sem); if (vmf->flags & FAULT_FLAG_WRITE) sb_end_pagefault(inode->i_sb); return ret; |
f7ca90b16
|
58 |
} |
e7b1ea2ad
|
59 60 61 |
static int ext2_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned int flags) { |
5726b27b0
|
62 63 64 65 66 67 68 69 70 |
struct inode *inode = file_inode(vma->vm_file); struct ext2_inode_info *ei = EXT2_I(inode); int ret; if (flags & FAULT_FLAG_WRITE) { sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); } down_read(&ei->dax_sem); |
02fbd1397
|
71 |
ret = __dax_pmd_fault(vma, addr, pmd, flags, ext2_get_block); |
5726b27b0
|
72 73 74 75 76 |
up_read(&ei->dax_sem); if (flags & FAULT_FLAG_WRITE) sb_end_pagefault(inode->i_sb); return ret; |
e7b1ea2ad
|
77 |
} |
5726b27b0
|
78 79 80 81 82 |
static int ext2_dax_pfn_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct inode *inode = file_inode(vma->vm_file); struct ext2_inode_info *ei = EXT2_I(inode); |
5726b27b0
|
83 |
loff_t size; |
80b4adcaf
|
84 |
int ret; |
5726b27b0
|
85 86 87 88 89 90 91 92 93 |
sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); down_read(&ei->dax_sem); /* check that the faulting page hasn't raced with truncate */ size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (vmf->pgoff >= size) ret = VM_FAULT_SIGBUS; |
80b4adcaf
|
94 95 |
else ret = dax_pfn_mkwrite(vma, vmf); |
5726b27b0
|
96 97 98 99 |
up_read(&ei->dax_sem); sb_end_pagefault(inode->i_sb); return ret; |
f7ca90b16
|
100 101 102 103 |
} static const struct vm_operations_struct ext2_dax_vm_ops = { .fault = ext2_dax_fault, |
e7b1ea2ad
|
104 |
.pmd_fault = ext2_dax_pmd_fault, |
1e9d180ba
|
105 |
.page_mkwrite = ext2_dax_fault, |
5726b27b0
|
106 |
.pfn_mkwrite = ext2_dax_pfn_mkwrite, |
f7ca90b16
|
107 108 109 110 111 112 113 114 115 |
}; static int ext2_file_mmap(struct file *file, struct vm_area_struct *vma) { if (!IS_DAX(file_inode(file))) return generic_file_mmap(file, vma); file_accessed(file); vma->vm_ops = &ext2_dax_vm_ops; |
e7b1ea2ad
|
116 |
vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; |
f7ca90b16
|
117 118 119 120 121 |
return 0; } #else #define ext2_file_mmap generic_file_mmap #endif |
1da177e4c
|
122 |
/* |
a6739af8b
|
123 124 125 |
* Called when filp is released. This happens when all file descriptors * for a single struct file are closed. Note that different open() calls * for the same file yield different struct file structures. |
1da177e4c
|
126 127 128 |
*/ static int ext2_release_file (struct inode * inode, struct file * filp) { |
a686cd898
|
129 130 131 132 133 |
if (filp->f_mode & FMODE_WRITE) { mutex_lock(&EXT2_I(inode)->truncate_mutex); ext2_discard_reservation(inode); mutex_unlock(&EXT2_I(inode)->truncate_mutex); } |
1da177e4c
|
134 135 |
return 0; } |
02c24a821
|
136 |
int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
48bde86df
|
137 138 |
{ int ret; |
7ea808591
|
139 |
struct super_block *sb = file->f_mapping->host->i_sb; |
48bde86df
|
140 |
struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; |
02c24a821
|
141 |
ret = generic_file_fsync(file, start, end, datasync); |
48bde86df
|
142 143 144 145 146 147 148 149 |
if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { /* We don't really know where the IO error happened... */ ext2_error(sb, __func__, "detected IO error when writing metadata buffers"); ret = -EIO; } return ret; } |
1da177e4c
|
150 151 152 153 |
/* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. */ |
4b6f5d20b
|
154 |
const struct file_operations ext2_file_operations = { |
1da177e4c
|
155 |
.llseek = generic_file_llseek, |
aad4f8bb4
|
156 |
.read_iter = generic_file_read_iter, |
8174202b3
|
157 |
.write_iter = generic_file_write_iter, |
14f9f7b28
|
158 |
.unlocked_ioctl = ext2_ioctl, |
e322ff07f
|
159 160 161 |
#ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif |
f7ca90b16
|
162 |
.mmap = ext2_file_mmap, |
907f4554e
|
163 |
.open = dquot_file_open, |
1da177e4c
|
164 |
.release = ext2_release_file, |
48bde86df
|
165 |
.fsync = ext2_fsync, |
5274f052e
|
166 |
.splice_read = generic_file_splice_read, |
8d0207652
|
167 |
.splice_write = iter_file_splice_write, |
1da177e4c
|
168 |
}; |
754661f14
|
169 |
const struct inode_operations ext2_file_inode_operations = { |
1da177e4c
|
170 171 172 173 174 175 176 |
#ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, |
4e34e719e
|
177 |
.get_acl = ext2_get_acl, |
64e178a71
|
178 |
.set_acl = ext2_set_acl, |
68c9d702b
|
179 |
.fiemap = ext2_fiemap, |
1da177e4c
|
180 |
}; |