Blame view
fs/ext4/file.c
17.8 KB
ac27a0ec1 [PATCH] ext4: ini... |
1 |
/* |
617ba13b3 [PATCH] ext4: ren... |
2 |
* linux/fs/ext4/file.c |
ac27a0ec1 [PATCH] ext4: ini... |
3 4 5 6 7 8 9 10 11 12 13 14 |
* * 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 * |
617ba13b3 [PATCH] ext4: ren... |
15 |
* ext4 fs regular file handling primitives |
ac27a0ec1 [PATCH] ext4: ini... |
16 17 18 19 20 21 22 |
* * 64-bit file support on 64-bit platforms by Jakub Jelinek * (jj@sunsite.ms.mff.cuni.cz) */ #include <linux/time.h> #include <linux/fs.h> |
bc0b0d6d6 ext4: update the ... |
23 24 |
#include <linux/mount.h> #include <linux/path.h> |
c94c2acf8 dax: move DAX-rel... |
25 |
#include <linux/dax.h> |
871a29315 dquot: cleanup dq... |
26 |
#include <linux/quotaops.h> |
c8c0df241 ext4: introduce l... |
27 |
#include <linux/pagevec.h> |
e2e40f2c1 fs: move struct k... |
28 |
#include <linux/uio.h> |
3dcf54515 ext4: move header... |
29 30 |
#include "ext4.h" #include "ext4_jbd2.h" |
ac27a0ec1 [PATCH] ext4: ini... |
31 32 33 34 35 |
#include "xattr.h" #include "acl.h" /* * Called when an inode is released. Note that this is different |
617ba13b3 [PATCH] ext4: ren... |
36 |
* from ext4_file_open: open gets called at every open, but release |
ac27a0ec1 [PATCH] ext4: ini... |
37 38 |
* gets called only when /all/ the files are closed. */ |
af5bc92dd ext4: Fix whitesp... |
39 |
static int ext4_release_file(struct inode *inode, struct file *filp) |
ac27a0ec1 [PATCH] ext4: ini... |
40 |
{ |
19f5fb7ad ext4: Use bitops ... |
41 |
if (ext4_test_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE)) { |
7d8f9f7d1 ext4: Automatical... |
42 |
ext4_alloc_da_blocks(inode); |
19f5fb7ad ext4: Use bitops ... |
43 |
ext4_clear_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); |
7d8f9f7d1 ext4: Automatical... |
44 |
} |
ac27a0ec1 [PATCH] ext4: ini... |
45 46 |
/* if we are the last writer on the inode, drop the block reservation */ if ((filp->f_mode & FMODE_WRITE) && |
d6014301b ext4: Fix discard... |
47 48 |
(atomic_read(&inode->i_writecount) == 1) && !EXT4_I(inode)->i_reserved_data_blocks) |
ac27a0ec1 [PATCH] ext4: ini... |
49 |
{ |
0e855ac8b ext4: Convert tru... |
50 |
down_write(&EXT4_I(inode)->i_data_sem); |
c2ea3fde6 ext4: Remove old ... |
51 |
ext4_discard_preallocations(inode); |
0e855ac8b ext4: Convert tru... |
52 |
up_write(&EXT4_I(inode)->i_data_sem); |
ac27a0ec1 [PATCH] ext4: ini... |
53 54 |
} if (is_dx(inode) && filp->private_data) |
617ba13b3 [PATCH] ext4: ren... |
55 |
ext4_htree_free_dir_info(filp->private_data); |
ac27a0ec1 [PATCH] ext4: ini... |
56 57 58 |
return 0; } |
c197855ea ext4: make local ... |
59 |
static void ext4_unwritten_wait(struct inode *inode) |
e9e3bcecf ext4: serialize u... |
60 61 |
{ wait_queue_head_t *wq = ext4_ioend_wq(inode); |
e27f41e1b ext4: give i_aiod... |
62 |
wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_unwritten) == 0)); |
e9e3bcecf ext4: serialize u... |
63 64 65 66 67 68 69 70 71 72 73 74 |
} /* * This tests whether the IO in question is block-aligned or not. * Ext4 utilizes unwritten extents when hole-filling during direct IO, and they * are converted to written only after the IO is complete. Until they are * mapped, these blocks appear as holes, so dio_zero_block() will assume that * it needs to zero out portions of the start and/or end block. If 2 AIO * threads are at work on the same unwritten block, they must be synchronized * or one thread will zero the other's data, causing corruption. */ static int |
9b884164d convert ext4 to -... |
75 |
ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos) |
e9e3bcecf ext4: serialize u... |
76 77 78 |
{ struct super_block *sb = inode->i_sb; int blockmask = sb->s_blocksize - 1; |
e9e3bcecf ext4: serialize u... |
79 |
|
6e6358fc3 ext4: use i_size_... |
80 |
if (pos >= i_size_read(inode)) |
e9e3bcecf ext4: serialize u... |
81 |
return 0; |
9b884164d convert ext4 to -... |
82 |
if ((pos | iov_iter_alignment(from)) & blockmask) |
e9e3bcecf ext4: serialize u... |
83 84 85 86 |
return 1; return 0; } |
ac27a0ec1 [PATCH] ext4: ini... |
87 |
static ssize_t |
9b884164d convert ext4 to -... |
88 |
ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
ac27a0ec1 [PATCH] ext4: ini... |
89 |
{ |
8ad2850f4 ext4: move ext4_f... |
90 |
struct inode *inode = file_inode(iocb->ki_filp); |
2ba48ce51 mirror O_APPEND a... |
91 |
int o_direct = iocb->ki_flags & IOCB_DIRECT; |
e142d0526 ext4: use i_mutex... |
92 |
int unaligned_aio = 0; |
4bd809dbb ext4: don't take ... |
93 |
int overwrite = 0; |
8563000d3 ext4: use consist... |
94 |
ssize_t ret; |
7608e6104 ext4: inline gene... |
95 |
|
e142d0526 ext4: use i_mutex... |
96 97 98 99 |
inode_lock(inode); ret = generic_write_checks(iocb, from); if (ret <= 0) goto out; |
e2b465745 ext4: store maxby... |
100 |
/* |
e142d0526 ext4: use i_mutex... |
101 102 103 |
* Unaligned direct AIO must be serialized among each other as zeroing * of partial blocks of two competing unaligned AIOs can result in data * corruption. |
f5ccfe1dd ext4: fix locking... |
104 |
*/ |
e142d0526 ext4: use i_mutex... |
105 |
if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && |
f5ccfe1dd ext4: fix locking... |
106 |
!is_sync_kiocb(iocb) && |
e142d0526 ext4: use i_mutex... |
107 108 |
ext4_unaligned_aio(inode, from, iocb->ki_pos)) { unaligned_aio = 1; |
f5ccfe1dd ext4: fix locking... |
109 110 |
ext4_unwritten_wait(inode); } |
f5ccfe1dd ext4: fix locking... |
111 |
/* |
e2b465745 ext4: store maxby... |
112 113 114 |
* If we have encountered a bitmap-format file, the size limit * is smaller than s_maxbytes, which is for extent-mapped files. */ |
12e9b8920 ext4: Use bitops ... |
115 |
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { |
e2b465745 ext4: store maxby... |
116 |
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
ac27a0ec1 [PATCH] ext4: ini... |
117 |
|
3309dd04c switch generic_wr... |
118 |
if (iocb->ki_pos >= sbi->s_bitmap_maxbytes) { |
f5ccfe1dd ext4: fix locking... |
119 |
ret = -EFBIG; |
e768d7ff7 ext4_file_write_i... |
120 |
goto out; |
f5ccfe1dd ext4: fix locking... |
121 |
} |
3309dd04c switch generic_wr... |
122 |
iov_iter_truncate(from, sbi->s_bitmap_maxbytes - iocb->ki_pos); |
e2b465745 ext4: store maxby... |
123 |
} |
a41537e69 ext4: prevent bug... |
124 |
iocb->private = &overwrite; |
7ed07ba8c ext4: factor out ... |
125 |
if (o_direct) { |
3309dd04c switch generic_wr... |
126 127 |
size_t length = iov_iter_count(from); loff_t pos = iocb->ki_pos; |
8ad2850f4 ext4: move ext4_f... |
128 |
|
8ad2850f4 ext4: move ext4_f... |
129 |
/* check whether we do a DIO overwrite or not */ |
e142d0526 ext4: use i_mutex... |
130 |
if (ext4_should_dioread_nolock(inode) && !unaligned_aio && |
4b0524aae ext4: allow unloc... |
131 |
pos + length <= i_size_read(inode)) { |
8ad2850f4 ext4: move ext4_f... |
132 133 134 135 136 |
struct ext4_map_blocks map; unsigned int blkbits = inode->i_blkbits; int err, len; map.m_lblk = pos >> blkbits; |
518eaa638 ext4: create EXT4... |
137 |
map.m_len = EXT4_MAX_BLOCKS(length, pos, blkbits); |
8ad2850f4 ext4: move ext4_f... |
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
len = map.m_len; err = ext4_map_blocks(NULL, inode, &map, 0); /* * 'err==len' means that all of blocks has * been preallocated no matter they are * initialized or not. For excluding * unwritten extents, we need to check * m_flags. There are two conditions that * indicate for initialized extents. 1) If we * hit extent cache, EXT4_MAP_MAPPED flag is * returned; 2) If we do a real lookup, * non-flags are returned. So we should check * these two conditions. */ if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) overwrite = 1; } |
f5ccfe1dd ext4: fix locking... |
156 |
} |
7608e6104 ext4: inline gene... |
157 |
|
9b884164d convert ext4 to -... |
158 |
ret = __generic_file_write_iter(iocb, from); |
5955102c9 wrappers for ->i_... |
159 |
inode_unlock(inode); |
7608e6104 ext4: inline gene... |
160 |
|
e25922176 fs: simplify the ... |
161 162 |
if (ret > 0) ret = generic_write_sync(iocb, ret); |
e9e3bcecf ext4: serialize u... |
163 |
|
e768d7ff7 ext4_file_write_i... |
164 165 166 |
return ret; out: |
5955102c9 wrappers for ->i_... |
167 |
inode_unlock(inode); |
e9e3bcecf ext4: serialize u... |
168 |
return ret; |
ac27a0ec1 [PATCH] ext4: ini... |
169 |
} |
923ae0ff9 ext4: add DAX fun... |
170 171 172 |
#ifdef CONFIG_FS_DAX static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { |
01a33b4ac ext4: start trans... |
173 174 |
int result; handle_t *handle = NULL; |
ea3d7209c ext4: fix races b... |
175 176 |
struct inode *inode = file_inode(vma->vm_file); struct super_block *sb = inode->i_sb; |
01a33b4ac ext4: start trans... |
177 178 179 180 181 |
bool write = vmf->flags & FAULT_FLAG_WRITE; if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); |
ea3d7209c ext4: fix races b... |
182 |
down_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
183 184 |
handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, EXT4_DATA_TRANS_BLOCKS(sb)); |
ea3d7209c ext4: fix races b... |
185 186 |
} else down_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
187 188 189 190 |
if (IS_ERR(handle)) result = VM_FAULT_SIGBUS; else |
6b524995a dax: remote unuse... |
191 |
result = dax_fault(vma, vmf, ext4_dax_get_block); |
01a33b4ac ext4: start trans... |
192 193 194 195 |
if (write) { if (!IS_ERR(handle)) ext4_journal_stop(handle); |
ea3d7209c ext4: fix races b... |
196 |
up_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
197 |
sb_end_pagefault(sb); |
ea3d7209c ext4: fix races b... |
198 199 |
} else up_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
200 201 |
return result; |
923ae0ff9 ext4: add DAX fun... |
202 |
} |
11bd1a9ec ext4: huge page f... |
203 204 205 |
static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned int flags) { |
01a33b4ac ext4: start trans... |
206 207 208 209 210 211 212 213 214 |
int result; handle_t *handle = NULL; struct inode *inode = file_inode(vma->vm_file); struct super_block *sb = inode->i_sb; bool write = flags & FAULT_FLAG_WRITE; if (write) { sb_start_pagefault(sb); file_update_time(vma->vm_file); |
ea3d7209c ext4: fix races b... |
215 |
down_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
216 217 218 |
handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, ext4_chunk_trans_blocks(inode, PMD_SIZE / PAGE_SIZE)); |
ea3d7209c ext4: fix races b... |
219 220 |
} else down_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
221 222 223 224 |
if (IS_ERR(handle)) result = VM_FAULT_SIGBUS; else |
6b524995a dax: remote unuse... |
225 |
result = dax_pmd_fault(vma, addr, pmd, flags, |
02fbd1397 dax: Remove compl... |
226 |
ext4_dax_get_block); |
01a33b4ac ext4: start trans... |
227 228 229 230 |
if (write) { if (!IS_ERR(handle)) ext4_journal_stop(handle); |
ea3d7209c ext4: fix races b... |
231 |
up_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
232 |
sb_end_pagefault(sb); |
ea3d7209c ext4: fix races b... |
233 234 |
} else up_read(&EXT4_I(inode)->i_mmap_sem); |
01a33b4ac ext4: start trans... |
235 236 |
return result; |
11bd1a9ec ext4: huge page f... |
237 |
} |
ea3d7209c ext4: fix races b... |
238 |
/* |
1e9d180ba ext2, ext4: fix i... |
239 |
* Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_fault() |
ea3d7209c ext4: fix races b... |
240 241 242 243 244 245 246 247 248 249 250 251 |
* handler we check for races agaist truncate. Note that since we cycle through * i_mmap_sem, we are sure that also any hole punching that began before we * were called is finished by now and so if it included part of the file we * are working on, our pte will get unmapped and the check for pte_same() in * wp_pfn_shared() fails. Thus fault gets retried and things work out as * desired. */ static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct inode *inode = file_inode(vma->vm_file); struct super_block *sb = inode->i_sb; |
ea3d7209c ext4: fix races b... |
252 |
loff_t size; |
d5be7a03b ext4: call dax_pf... |
253 |
int ret; |
ea3d7209c ext4: fix races b... |
254 255 256 257 258 259 260 |
sb_start_pagefault(sb); file_update_time(vma->vm_file); down_read(&EXT4_I(inode)->i_mmap_sem); size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (vmf->pgoff >= size) ret = VM_FAULT_SIGBUS; |
d5be7a03b ext4: call dax_pf... |
261 262 |
else ret = dax_pfn_mkwrite(vma, vmf); |
ea3d7209c ext4: fix races b... |
263 264 265 266 |
up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(sb); return ret; |
923ae0ff9 ext4: add DAX fun... |
267 268 269 270 |
} static const struct vm_operations_struct ext4_dax_vm_ops = { .fault = ext4_dax_fault, |
11bd1a9ec ext4: huge page f... |
271 |
.pmd_fault = ext4_dax_pmd_fault, |
1e9d180ba ext2, ext4: fix i... |
272 |
.page_mkwrite = ext4_dax_fault, |
ea3d7209c ext4: fix races b... |
273 |
.pfn_mkwrite = ext4_dax_pfn_mkwrite, |
923ae0ff9 ext4: add DAX fun... |
274 275 276 277 |
}; #else #define ext4_dax_vm_ops ext4_file_vm_ops #endif |
f0f37e2f7 const: mark struc... |
278 |
static const struct vm_operations_struct ext4_file_vm_ops = { |
ea3d7209c ext4: fix races b... |
279 |
.fault = ext4_filemap_fault, |
f1820361f mm: implement ->m... |
280 |
.map_pages = filemap_map_pages, |
2e9ee8503 ext4: Use page_mk... |
281 282 283 284 285 |
.page_mkwrite = ext4_page_mkwrite, }; static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) { |
c9c7429c2 ext4 crypto: impl... |
286 287 288 |
struct inode *inode = file->f_mapping->host; if (ext4_encrypted_inode(inode)) { |
a7550b30a ext4 crypto: migr... |
289 |
int err = fscrypt_get_encryption_info(inode); |
c9c7429c2 ext4 crypto: impl... |
290 291 |
if (err) return 0; |
a7550b30a ext4 crypto: migr... |
292 |
if (!fscrypt_has_encryption_key(inode)) |
abdd438b2 ext4 crypto: hand... |
293 |
return -ENOKEY; |
c9c7429c2 ext4 crypto: impl... |
294 |
} |
2e9ee8503 ext4: Use page_mk... |
295 |
file_accessed(file); |
923ae0ff9 ext4: add DAX fun... |
296 297 |
if (IS_DAX(file_inode(file))) { vma->vm_ops = &ext4_dax_vm_ops; |
11bd1a9ec ext4: huge page f... |
298 |
vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; |
923ae0ff9 ext4: add DAX fun... |
299 300 301 |
} else { vma->vm_ops = &ext4_file_vm_ops; } |
2e9ee8503 ext4: Use page_mk... |
302 303 |
return 0; } |
bc0b0d6d6 ext4: update the ... |
304 305 306 307 308 |
static int ext4_file_open(struct inode * inode, struct file * filp) { struct super_block *sb = inode->i_sb; struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct vfsmount *mnt = filp->f_path.mnt; |
9dd78d8c9 ext4: use dget_pa... |
309 |
struct dentry *dir; |
bc0b0d6d6 ext4: update the ... |
310 311 |
struct path path; char buf[64], *cp; |
c9c7429c2 ext4 crypto: impl... |
312 |
int ret; |
bc0b0d6d6 ext4: update the ... |
313 314 315 316 317 318 319 320 321 322 323 |
if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) && !(sb->s_flags & MS_RDONLY))) { sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; /* * Sample where the filesystem has been mounted and * store it in the superblock for sysadmin convenience * when trying to sort through large numbers of block * devices or filesystem images. */ memset(buf, 0, sizeof(buf)); |
3899167db Get rid of mnt_mo... |
324 325 |
path.mnt = mnt; path.dentry = mnt->mnt_root; |
bc0b0d6d6 ext4: update the ... |
326 |
cp = d_path(&path, buf, sizeof(buf)); |
bc0b0d6d6 ext4: update the ... |
327 |
if (!IS_ERR(cp)) { |
044ce47fe ext4: convert las... |
328 329 |
handle_t *handle; int err; |
9924a92a8 ext4: pass contex... |
330 |
handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); |
044ce47fe ext4: convert las... |
331 332 |
if (IS_ERR(handle)) return PTR_ERR(handle); |
5d6012553 ext4: add missing... |
333 |
BUFFER_TRACE(sbi->s_sbh, "get_write_access"); |
044ce47fe ext4: convert las... |
334 335 336 337 338 |
err = ext4_journal_get_write_access(handle, sbi->s_sbh); if (err) { ext4_journal_stop(handle); return err; } |
cf8039036 ext4: prevent sta... |
339 340 |
strlcpy(sbi->s_es->s_last_mounted, cp, sizeof(sbi->s_es->s_last_mounted)); |
044ce47fe ext4: convert las... |
341 342 |
ext4_handle_dirty_super(handle, sb); ext4_journal_stop(handle); |
bc0b0d6d6 ext4: update the ... |
343 344 |
} } |
abdd438b2 ext4 crypto: hand... |
345 |
if (ext4_encrypted_inode(inode)) { |
a7550b30a ext4 crypto: migr... |
346 |
ret = fscrypt_get_encryption_info(inode); |
abdd438b2 ext4 crypto: hand... |
347 348 |
if (ret) return -EACCES; |
a7550b30a ext4 crypto: migr... |
349 |
if (!fscrypt_has_encryption_key(inode)) |
abdd438b2 ext4 crypto: hand... |
350 351 |
return -ENOKEY; } |
9dd78d8c9 ext4: use dget_pa... |
352 |
|
c0a37d487 ext4: use file_de... |
353 |
dir = dget_parent(file_dentry(filp)); |
9dd78d8c9 ext4: use dget_pa... |
354 |
if (ext4_encrypted_inode(d_inode(dir)) && |
a7550b30a ext4 crypto: migr... |
355 |
!fscrypt_has_permitted_context(d_inode(dir), inode)) { |
ff978b09f ext4 crypto: move... |
356 |
ext4_warning(inode->i_sb, |
8d2ae1cbe ext4: remove trai... |
357 |
"Inconsistent encryption contexts: %lu/%lu", |
9dd78d8c9 ext4: use dget_pa... |
358 |
(unsigned long) d_inode(dir)->i_ino, |
ff978b09f ext4 crypto: move... |
359 |
(unsigned long) inode->i_ino); |
9dd78d8c9 ext4: use dget_pa... |
360 |
dput(dir); |
ff978b09f ext4 crypto: move... |
361 362 |
return -EPERM; } |
9dd78d8c9 ext4: use dget_pa... |
363 |
dput(dir); |
8aefcd557 ext4: dynamically... |
364 365 366 367 |
/* * Set up the jbd2_inode if we are opening the inode for * writing and the journal is present */ |
a361293f5 jbd2: Fix oops in... |
368 |
if (filp->f_mode & FMODE_WRITE) { |
c9c7429c2 ext4 crypto: impl... |
369 |
ret = ext4_inode_attach_jinode(inode); |
a361293f5 jbd2: Fix oops in... |
370 371 |
if (ret < 0) return ret; |
8aefcd557 ext4: dynamically... |
372 |
} |
abdd438b2 ext4 crypto: hand... |
373 |
return dquot_file_open(inode, filp); |
bc0b0d6d6 ext4: update the ... |
374 |
} |
e0d10bfa9 ext4: improve lls... |
375 |
/* |
c8c0df241 ext4: introduce l... |
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
* Here we use ext4_map_blocks() to get a block mapping for a extent-based * file rather than ext4_ext_walk_space() because we can introduce * SEEK_DATA/SEEK_HOLE for block-mapped and extent-mapped file at the same * function. When extent status tree has been fully implemented, it will * track all extent status for a file and we can directly use it to * retrieve the offset for SEEK_DATA/SEEK_HOLE. */ /* * When we retrieve the offset for SEEK_DATA/SEEK_HOLE, we would need to * lookup page cache to check whether or not there has some data between * [startoff, endoff] because, if this range contains an unwritten extent, * we determine this extent as a data or a hole according to whether the * page cache has data or not. */ |
ad7fefb10 Revert "ext4: fix... |
391 392 |
static int ext4_find_unwritten_pgoff(struct inode *inode, int whence, |
2d90c160e ext4: more effici... |
393 |
ext4_lblk_t end_blk, |
ad7fefb10 Revert "ext4: fix... |
394 |
loff_t *offset) |
c8c0df241 ext4: introduce l... |
395 396 |
{ struct pagevec pvec; |
ad7fefb10 Revert "ext4: fix... |
397 |
unsigned int blkbits; |
c8c0df241 ext4: introduce l... |
398 399 |
pgoff_t index; pgoff_t end; |
ad7fefb10 Revert "ext4: fix... |
400 |
loff_t endoff; |
c8c0df241 ext4: introduce l... |
401 402 403 |
loff_t startoff; loff_t lastoff; int found = 0; |
ad7fefb10 Revert "ext4: fix... |
404 |
blkbits = inode->i_sb->s_blocksize_bits; |
c8c0df241 ext4: introduce l... |
405 406 |
startoff = *offset; lastoff = startoff; |
2d90c160e ext4: more effici... |
407 |
endoff = (loff_t)end_blk << blkbits; |
c8c0df241 ext4: introduce l... |
408 |
|
09cbfeaf1 mm, fs: get rid o... |
409 410 |
index = startoff >> PAGE_SHIFT; end = endoff >> PAGE_SHIFT; |
c8c0df241 ext4: introduce l... |
411 412 413 414 415 416 417 418 419 420 |
pagevec_init(&pvec, 0); do { int i, num; unsigned long nr_pages; num = min_t(pgoff_t, end - index, PAGEVEC_SIZE); nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, (pgoff_t)num); if (nr_pages == 0) { |
965c8e59c lseek: the "whenc... |
421 |
if (whence == SEEK_DATA) |
c8c0df241 ext4: introduce l... |
422 |
break; |
965c8e59c lseek: the "whenc... |
423 |
BUG_ON(whence != SEEK_HOLE); |
c8c0df241 ext4: introduce l... |
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
/* * If this is the first time to go into the loop and * offset is not beyond the end offset, it will be a * hole at this offset */ if (lastoff == startoff || lastoff < endoff) found = 1; break; } /* * If this is the first time to go into the loop and * offset is smaller than the first page offset, it will be a * hole at this offset. */ |
965c8e59c lseek: the "whenc... |
439 |
if (lastoff == startoff && whence == SEEK_HOLE && |
c8c0df241 ext4: introduce l... |
440 441 442 443 444 445 446 447 448 449 450 451 452 |
lastoff < page_offset(pvec.pages[0])) { found = 1; break; } for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; struct buffer_head *bh, *head; /* * If the current offset is not beyond the end of given * range, it will be a hole. */ |
965c8e59c lseek: the "whenc... |
453 |
if (lastoff < endoff && whence == SEEK_HOLE && |
c8c0df241 ext4: introduce l... |
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
page->index > end) { found = 1; *offset = lastoff; goto out; } lock_page(page); if (unlikely(page->mapping != inode->i_mapping)) { unlock_page(page); continue; } if (!page_has_buffers(page)) { unlock_page(page); continue; } if (page_has_buffers(page)) { lastoff = page_offset(page); bh = head = page_buffers(page); do { if (buffer_uptodate(bh) || buffer_unwritten(bh)) { |
965c8e59c lseek: the "whenc... |
478 |
if (whence == SEEK_DATA) |
c8c0df241 ext4: introduce l... |
479 480 |
found = 1; } else { |
965c8e59c lseek: the "whenc... |
481 |
if (whence == SEEK_HOLE) |
c8c0df241 ext4: introduce l... |
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
found = 1; } if (found) { *offset = max_t(loff_t, startoff, lastoff); unlock_page(page); goto out; } lastoff += bh->b_size; bh = bh->b_this_page; } while (bh != head); } lastoff = page_offset(page) + PAGE_SIZE; unlock_page(page); } /* * The no. of pages is less than our desired, that would be a * hole in there. */ |
965c8e59c lseek: the "whenc... |
503 |
if (nr_pages < num && whence == SEEK_HOLE) { |
c8c0df241 ext4: introduce l... |
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
found = 1; *offset = lastoff; break; } index = pvec.pages[i - 1]->index + 1; pagevec_release(&pvec); } while (index <= end); out: pagevec_release(&pvec); return found; } /* * ext4_seek_data() retrieves the offset for SEEK_DATA. */ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) { struct inode *inode = file->f_mapping->host; |
ad7fefb10 Revert "ext4: fix... |
524 525 526 527 |
struct extent_status es; ext4_lblk_t start, last, end; loff_t dataoff, isize; int blkbits; |
2d90c160e ext4: more effici... |
528 |
int ret; |
c8c0df241 ext4: introduce l... |
529 |
|
5955102c9 wrappers for ->i_... |
530 |
inode_lock(inode); |
ad7fefb10 Revert "ext4: fix... |
531 532 533 |
isize = i_size_read(inode); if (offset >= isize) { |
5955102c9 wrappers for ->i_... |
534 |
inode_unlock(inode); |
c8c0df241 ext4: introduce l... |
535 536 |
return -ENXIO; } |
ad7fefb10 Revert "ext4: fix... |
537 538 539 540 541 542 543 544 |
blkbits = inode->i_sb->s_blocksize_bits; start = offset >> blkbits; last = start; end = isize >> blkbits; dataoff = offset; do { |
2d90c160e ext4: more effici... |
545 546 547 548 549 550 551 |
ret = ext4_get_next_extent(inode, last, end - last + 1, &es); if (ret <= 0) { /* No extent found -> no data */ if (ret == 0) ret = -ENXIO; inode_unlock(inode); return ret; |
ad7fefb10 Revert "ext4: fix... |
552 |
} |
c8c0df241 ext4: introduce l... |
553 |
|
2d90c160e ext4: more effici... |
554 555 556 557 |
last = es.es_lblk; if (last != start) dataoff = (loff_t)last << blkbits; if (!ext4_es_is_unwritten(&es)) |
c8c0df241 ext4: introduce l... |
558 |
break; |
c8c0df241 ext4: introduce l... |
559 |
|
ad7fefb10 Revert "ext4: fix... |
560 561 562 563 564 |
/* * If there is a unwritten extent at this offset, * it will be as a data or a hole according to page * cache that has data or not. */ |
2d90c160e ext4: more effici... |
565 566 567 568 |
if (ext4_find_unwritten_pgoff(inode, SEEK_DATA, es.es_lblk + es.es_len, &dataoff)) break; last += es.es_len; |
ad7fefb10 Revert "ext4: fix... |
569 |
dataoff = (loff_t)last << blkbits; |
2d90c160e ext4: more effici... |
570 |
cond_resched(); |
ad7fefb10 Revert "ext4: fix... |
571 |
} while (last <= end); |
c8c0df241 ext4: introduce l... |
572 |
|
5955102c9 wrappers for ->i_... |
573 |
inode_unlock(inode); |
c8c0df241 ext4: introduce l... |
574 |
|
ad7fefb10 Revert "ext4: fix... |
575 576 577 578 |
if (dataoff > isize) return -ENXIO; return vfs_setpos(file, dataoff, maxsize); |
c8c0df241 ext4: introduce l... |
579 580 581 |
} /* |
ad7fefb10 Revert "ext4: fix... |
582 |
* ext4_seek_hole() retrieves the offset for SEEK_HOLE. |
c8c0df241 ext4: introduce l... |
583 584 585 586 |
*/ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) { struct inode *inode = file->f_mapping->host; |
ad7fefb10 Revert "ext4: fix... |
587 588 589 590 |
struct extent_status es; ext4_lblk_t start, last, end; loff_t holeoff, isize; int blkbits; |
2d90c160e ext4: more effici... |
591 |
int ret; |
c8c0df241 ext4: introduce l... |
592 |
|
5955102c9 wrappers for ->i_... |
593 |
inode_lock(inode); |
ad7fefb10 Revert "ext4: fix... |
594 595 596 |
isize = i_size_read(inode); if (offset >= isize) { |
5955102c9 wrappers for ->i_... |
597 |
inode_unlock(inode); |
c8c0df241 ext4: introduce l... |
598 599 |
return -ENXIO; } |
ad7fefb10 Revert "ext4: fix... |
600 601 602 603 604 |
blkbits = inode->i_sb->s_blocksize_bits; start = offset >> blkbits; last = start; end = isize >> blkbits; holeoff = offset; |
c8c0df241 ext4: introduce l... |
605 |
|
ad7fefb10 Revert "ext4: fix... |
606 |
do { |
2d90c160e ext4: more effici... |
607 608 609 610 |
ret = ext4_get_next_extent(inode, last, end - last + 1, &es); if (ret < 0) { inode_unlock(inode); return ret; |
ad7fefb10 Revert "ext4: fix... |
611 |
} |
2d90c160e ext4: more effici... |
612 613 614 615 616 |
/* Found a hole? */ if (ret == 0 || es.es_lblk > last) { if (last != start) holeoff = (loff_t)last << blkbits; break; |
ad7fefb10 Revert "ext4: fix... |
617 |
} |
ad7fefb10 Revert "ext4: fix... |
618 619 620 621 622 |
/* * If there is a unwritten extent at this offset, * it will be as a data or a hole according to page * cache that has data or not. */ |
2d90c160e ext4: more effici... |
623 624 625 626 |
if (ext4_es_is_unwritten(&es) && ext4_find_unwritten_pgoff(inode, SEEK_HOLE, last + es.es_len, &holeoff)) break; |
ad7fefb10 Revert "ext4: fix... |
627 |
|
2d90c160e ext4: more effici... |
628 629 630 |
last += es.es_len; holeoff = (loff_t)last << blkbits; cond_resched(); |
ad7fefb10 Revert "ext4: fix... |
631 |
} while (last <= end); |
5955102c9 wrappers for ->i_... |
632 |
inode_unlock(inode); |
c8c0df241 ext4: introduce l... |
633 |
|
ad7fefb10 Revert "ext4: fix... |
634 635 636 637 |
if (holeoff > isize) holeoff = isize; return vfs_setpos(file, holeoff, maxsize); |
c8c0df241 ext4: introduce l... |
638 639 640 |
} /* |
ec7268ce2 ext4: use core vf... |
641 642 643 |
* ext4_llseek() handles both block-mapped and extent-mapped maxbytes values * by calling generic_file_llseek_size() with the appropriate maxbytes * value for each. |
e0d10bfa9 ext4: improve lls... |
644 |
*/ |
965c8e59c lseek: the "whenc... |
645 |
loff_t ext4_llseek(struct file *file, loff_t offset, int whence) |
e0d10bfa9 ext4: improve lls... |
646 647 648 649 650 651 652 653 |
{ struct inode *inode = file->f_mapping->host; loff_t maxbytes; if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; else maxbytes = inode->i_sb->s_maxbytes; |
e0d10bfa9 ext4: improve lls... |
654 |
|
965c8e59c lseek: the "whenc... |
655 |
switch (whence) { |
c8c0df241 ext4: introduce l... |
656 657 658 |
case SEEK_SET: case SEEK_CUR: case SEEK_END: |
965c8e59c lseek: the "whenc... |
659 |
return generic_file_llseek_size(file, offset, whence, |
c8c0df241 ext4: introduce l... |
660 661 662 663 664 665 666 667 |
maxbytes, i_size_read(inode)); case SEEK_DATA: return ext4_seek_data(file, offset, maxbytes); case SEEK_HOLE: return ext4_seek_hole(file, offset, maxbytes); } return -EINVAL; |
e0d10bfa9 ext4: improve lls... |
668 |
} |
617ba13b3 [PATCH] ext4: ren... |
669 |
const struct file_operations ext4_file_operations = { |
e0d10bfa9 ext4: improve lls... |
670 |
.llseek = ext4_llseek, |
aad4f8bb4 switch simple gen... |
671 |
.read_iter = generic_file_read_iter, |
9b884164d convert ext4 to -... |
672 |
.write_iter = ext4_file_write_iter, |
5cdd7b2d7 Convert ext4 to u... |
673 |
.unlocked_ioctl = ext4_ioctl, |
ac27a0ec1 [PATCH] ext4: ini... |
674 |
#ifdef CONFIG_COMPAT |
617ba13b3 [PATCH] ext4: ren... |
675 |
.compat_ioctl = ext4_compat_ioctl, |
ac27a0ec1 [PATCH] ext4: ini... |
676 |
#endif |
2e9ee8503 ext4: Use page_mk... |
677 |
.mmap = ext4_file_mmap, |
bc0b0d6d6 ext4: update the ... |
678 |
.open = ext4_file_open, |
617ba13b3 [PATCH] ext4: ren... |
679 680 |
.release = ext4_release_file, .fsync = ext4_sync_file, |
dbe6ec815 ext2/4, xfs: call... |
681 |
.get_unmapped_area = thp_get_unmapped_area, |
ac27a0ec1 [PATCH] ext4: ini... |
682 |
.splice_read = generic_file_splice_read, |
8d0207652 ->splice_write() ... |
683 |
.splice_write = iter_file_splice_write, |
2fe17c107 fallocate should ... |
684 |
.fallocate = ext4_fallocate, |
ac27a0ec1 [PATCH] ext4: ini... |
685 |
}; |
754661f14 [PATCH] mark stru... |
686 |
const struct inode_operations ext4_file_inode_operations = { |
617ba13b3 [PATCH] ext4: ren... |
687 |
.setattr = ext4_setattr, |
3e3398a08 ext4: delayed all... |
688 |
.getattr = ext4_getattr, |
617ba13b3 [PATCH] ext4: ren... |
689 |
.listxattr = ext4_listxattr, |
4e34e719e fs: take the ACL ... |
690 |
.get_acl = ext4_get_acl, |
64e178a71 ext2/3/4: use gen... |
691 |
.set_acl = ext4_set_acl, |
6873fa0de Hook ext4 to the ... |
692 |
.fiemap = ext4_fiemap, |
ac27a0ec1 [PATCH] ext4: ini... |
693 |
}; |