18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём) 88c2ecf20Sopenharmony_ci * Adrian Hunter 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * This file implements VFS file and inode operations for regular files, device 138c2ecf20Sopenharmony_ci * nodes and symlinks as well as address space operations. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * UBIFS uses 2 page flags: @PG_private and @PG_checked. @PG_private is set if 168c2ecf20Sopenharmony_ci * the page is dirty and is used for optimization purposes - dirty pages are 178c2ecf20Sopenharmony_ci * not budgeted so the flag shows that 'ubifs_write_end()' should not release 188c2ecf20Sopenharmony_ci * the budget for this page. The @PG_checked flag is set if full budgeting is 198c2ecf20Sopenharmony_ci * required for the page e.g., when it corresponds to a file hole or it is 208c2ecf20Sopenharmony_ci * beyond the file size. The budgeting is done in 'ubifs_write_begin()', because 218c2ecf20Sopenharmony_ci * it is OK to fail in this function, and the budget is released in 228c2ecf20Sopenharmony_ci * 'ubifs_write_end()'. So the @PG_private and @PG_checked flags carry 238c2ecf20Sopenharmony_ci * information about how the page was budgeted, to make it possible to release 248c2ecf20Sopenharmony_ci * the budget properly. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * A thing to keep in mind: inode @i_mutex is locked in most VFS operations we 278c2ecf20Sopenharmony_ci * implement. However, this is not true for 'ubifs_writepage()', which may be 288c2ecf20Sopenharmony_ci * called with @i_mutex unlocked. For example, when flusher thread is doing 298c2ecf20Sopenharmony_ci * background write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. 308c2ecf20Sopenharmony_ci * At "normal" work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. 318c2ecf20Sopenharmony_ci * in the "sys_write -> alloc_pages -> direct reclaim path". So, in 328c2ecf20Sopenharmony_ci * 'ubifs_writepage()' we are only guaranteed that the page is locked. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Similarly, @i_mutex is not always locked in 'ubifs_readpage()', e.g., the 358c2ecf20Sopenharmony_ci * read-ahead path does not lock it ("sys_read -> generic_file_aio_read -> 368c2ecf20Sopenharmony_ci * ondemand_readahead -> readpage"). In case of readahead, @I_SYNC flag is not 378c2ecf20Sopenharmony_ci * set as well. However, UBIFS disables readahead. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "ubifs.h" 418c2ecf20Sopenharmony_ci#include <linux/mount.h> 428c2ecf20Sopenharmony_ci#include <linux/slab.h> 438c2ecf20Sopenharmony_ci#include <linux/migrate.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int read_block(struct inode *inode, void *addr, unsigned int block, 468c2ecf20Sopenharmony_ci struct ubifs_data_node *dn) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 498c2ecf20Sopenharmony_ci int err, len, out_len; 508c2ecf20Sopenharmony_ci union ubifs_key key; 518c2ecf20Sopenharmony_ci unsigned int dlen; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci data_key_init(c, &key, inode->i_ino, block); 548c2ecf20Sopenharmony_ci err = ubifs_tnc_lookup(c, &key, dn); 558c2ecf20Sopenharmony_ci if (err) { 568c2ecf20Sopenharmony_ci if (err == -ENOENT) 578c2ecf20Sopenharmony_ci /* Not found, so it must be a hole */ 588c2ecf20Sopenharmony_ci memset(addr, 0, UBIFS_BLOCK_SIZE); 598c2ecf20Sopenharmony_ci return err; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci ubifs_assert(c, le64_to_cpu(dn->ch.sqnum) > 638c2ecf20Sopenharmony_ci ubifs_inode(inode)->creat_sqnum); 648c2ecf20Sopenharmony_ci len = le32_to_cpu(dn->size); 658c2ecf20Sopenharmony_ci if (len <= 0 || len > UBIFS_BLOCK_SIZE) 668c2ecf20Sopenharmony_ci goto dump; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(inode)) { 718c2ecf20Sopenharmony_ci err = ubifs_decrypt(inode, dn, &dlen, block); 728c2ecf20Sopenharmony_ci if (err) 738c2ecf20Sopenharmony_ci goto dump; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci out_len = UBIFS_BLOCK_SIZE; 778c2ecf20Sopenharmony_ci err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len, 788c2ecf20Sopenharmony_ci le16_to_cpu(dn->compr_type)); 798c2ecf20Sopenharmony_ci if (err || len != out_len) 808c2ecf20Sopenharmony_ci goto dump; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * Data length can be less than a full block, even for blocks that are 848c2ecf20Sopenharmony_ci * not the last in the file (e.g., as a result of making a hole and 858c2ecf20Sopenharmony_ci * appending data). Ensure that the remainder is zeroed out. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci if (len < UBIFS_BLOCK_SIZE) 888c2ecf20Sopenharmony_ci memset(addr + len, 0, UBIFS_BLOCK_SIZE - len); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cidump: 938c2ecf20Sopenharmony_ci ubifs_err(c, "bad data node (block %u, inode %lu)", 948c2ecf20Sopenharmony_ci block, inode->i_ino); 958c2ecf20Sopenharmony_ci ubifs_dump_node(c, dn, UBIFS_MAX_DATA_NODE_SZ); 968c2ecf20Sopenharmony_ci return -EINVAL; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int do_readpage(struct page *page) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci void *addr; 1028c2ecf20Sopenharmony_ci int err = 0, i; 1038c2ecf20Sopenharmony_ci unsigned int block, beyond; 1048c2ecf20Sopenharmony_ci struct ubifs_data_node *dn; 1058c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 1068c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 1078c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(inode); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx", 1108c2ecf20Sopenharmony_ci inode->i_ino, page->index, i_size, page->flags); 1118c2ecf20Sopenharmony_ci ubifs_assert(c, !PageChecked(page)); 1128c2ecf20Sopenharmony_ci ubifs_assert(c, !PagePrivate(page)); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci addr = kmap(page); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; 1178c2ecf20Sopenharmony_ci beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; 1188c2ecf20Sopenharmony_ci if (block >= beyond) { 1198c2ecf20Sopenharmony_ci /* Reading beyond inode */ 1208c2ecf20Sopenharmony_ci SetPageChecked(page); 1218c2ecf20Sopenharmony_ci memset(addr, 0, PAGE_SIZE); 1228c2ecf20Sopenharmony_ci goto out; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS); 1268c2ecf20Sopenharmony_ci if (!dn) { 1278c2ecf20Sopenharmony_ci err = -ENOMEM; 1288c2ecf20Sopenharmony_ci goto error; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci i = 0; 1328c2ecf20Sopenharmony_ci while (1) { 1338c2ecf20Sopenharmony_ci int ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (block >= beyond) { 1368c2ecf20Sopenharmony_ci /* Reading beyond inode */ 1378c2ecf20Sopenharmony_ci err = -ENOENT; 1388c2ecf20Sopenharmony_ci memset(addr, 0, UBIFS_BLOCK_SIZE); 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci ret = read_block(inode, addr, block, dn); 1418c2ecf20Sopenharmony_ci if (ret) { 1428c2ecf20Sopenharmony_ci err = ret; 1438c2ecf20Sopenharmony_ci if (err != -ENOENT) 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci } else if (block + 1 == beyond) { 1468c2ecf20Sopenharmony_ci int dlen = le32_to_cpu(dn->size); 1478c2ecf20Sopenharmony_ci int ilen = i_size & (UBIFS_BLOCK_SIZE - 1); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (ilen && ilen < dlen) 1508c2ecf20Sopenharmony_ci memset(addr + ilen, 0, dlen - ilen); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci if (++i >= UBIFS_BLOCKS_PER_PAGE) 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci block += 1; 1568c2ecf20Sopenharmony_ci addr += UBIFS_BLOCK_SIZE; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci if (err) { 1598c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 1608c2ecf20Sopenharmony_ci if (err == -ENOENT) { 1618c2ecf20Sopenharmony_ci /* Not found, so it must be a hole */ 1628c2ecf20Sopenharmony_ci SetPageChecked(page); 1638c2ecf20Sopenharmony_ci dbg_gen("hole"); 1648c2ecf20Sopenharmony_ci goto out_free; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci ubifs_err(c, "cannot read page %lu of inode %lu, error %d", 1678c2ecf20Sopenharmony_ci page->index, inode->i_ino, err); 1688c2ecf20Sopenharmony_ci goto error; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciout_free: 1728c2ecf20Sopenharmony_ci kfree(dn); 1738c2ecf20Sopenharmony_ciout: 1748c2ecf20Sopenharmony_ci SetPageUptodate(page); 1758c2ecf20Sopenharmony_ci ClearPageError(page); 1768c2ecf20Sopenharmony_ci flush_dcache_page(page); 1778c2ecf20Sopenharmony_ci kunmap(page); 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cierror: 1818c2ecf20Sopenharmony_ci kfree(dn); 1828c2ecf20Sopenharmony_ci ClearPageUptodate(page); 1838c2ecf20Sopenharmony_ci SetPageError(page); 1848c2ecf20Sopenharmony_ci flush_dcache_page(page); 1858c2ecf20Sopenharmony_ci kunmap(page); 1868c2ecf20Sopenharmony_ci return err; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/** 1908c2ecf20Sopenharmony_ci * release_new_page_budget - release budget of a new page. 1918c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * This is a helper function which releases budget corresponding to the budget 1948c2ecf20Sopenharmony_ci * of one new page of data. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_cistatic void release_new_page_budget(struct ubifs_info *c) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .recalculate = 1, .new_page = 1 }; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * release_existing_page_budget - release budget of an existing page. 2058c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * This is a helper function which releases budget corresponding to the budget 2088c2ecf20Sopenharmony_ci * of changing one one page of data which already exists on the flash media. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_cistatic void release_existing_page_budget(struct ubifs_info *c) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int write_begin_slow(struct address_space *mapping, 2188c2ecf20Sopenharmony_ci loff_t pos, unsigned len, struct page **pagep, 2198c2ecf20Sopenharmony_ci unsigned flags) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 2228c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 2238c2ecf20Sopenharmony_ci pgoff_t index = pos >> PAGE_SHIFT; 2248c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_page = 1 }; 2258c2ecf20Sopenharmony_ci int err, appending = !!(pos + len > inode->i_size); 2268c2ecf20Sopenharmony_ci struct page *page; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pos %llu, len %u, i_size %lld", 2298c2ecf20Sopenharmony_ci inode->i_ino, pos, len, inode->i_size); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * At the slow path we have to budget before locking the page, because 2338c2ecf20Sopenharmony_ci * budgeting may force write-back, which would wait on locked pages and 2348c2ecf20Sopenharmony_ci * deadlock if we had the page locked. At this point we do not know 2358c2ecf20Sopenharmony_ci * anything about the page, so assume that this is a new page which is 2368c2ecf20Sopenharmony_ci * written to a hole. This corresponds to largest budget. Later the 2378c2ecf20Sopenharmony_ci * budget will be amended if this is not true. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci if (appending) 2408c2ecf20Sopenharmony_ci /* We are appending data, budget for inode change */ 2418c2ecf20Sopenharmony_ci req.dirtied_ino = 1; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 2448c2ecf20Sopenharmony_ci if (unlikely(err)) 2458c2ecf20Sopenharmony_ci return err; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index, flags); 2488c2ecf20Sopenharmony_ci if (unlikely(!page)) { 2498c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 2508c2ecf20Sopenharmony_ci return -ENOMEM; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 2548c2ecf20Sopenharmony_ci if (!(pos & ~PAGE_MASK) && len == PAGE_SIZE) 2558c2ecf20Sopenharmony_ci SetPageChecked(page); 2568c2ecf20Sopenharmony_ci else { 2578c2ecf20Sopenharmony_ci err = do_readpage(page); 2588c2ecf20Sopenharmony_ci if (err) { 2598c2ecf20Sopenharmony_ci unlock_page(page); 2608c2ecf20Sopenharmony_ci put_page(page); 2618c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 2628c2ecf20Sopenharmony_ci return err; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (PagePrivate(page)) 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * The page is dirty, which means it was budgeted twice: 2708c2ecf20Sopenharmony_ci * o first time the budget was allocated by the task which 2718c2ecf20Sopenharmony_ci * made the page dirty and set the PG_private flag; 2728c2ecf20Sopenharmony_ci * o and then we budgeted for it for the second time at the 2738c2ecf20Sopenharmony_ci * very beginning of this function. 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * So what we have to do is to release the page budget we 2768c2ecf20Sopenharmony_ci * allocated. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci release_new_page_budget(c); 2798c2ecf20Sopenharmony_ci else if (!PageChecked(page)) 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * We are changing a page which already exists on the media. 2828c2ecf20Sopenharmony_ci * This means that changing the page does not make the amount 2838c2ecf20Sopenharmony_ci * of indexing information larger, and this part of the budget 2848c2ecf20Sopenharmony_ci * which we have already acquired may be released. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci ubifs_convert_page_budget(c); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (appending) { 2898c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * 'ubifs_write_end()' is optimized from the fast-path part of 2938c2ecf20Sopenharmony_ci * 'ubifs_write_begin()' and expects the @ui_mutex to be locked 2948c2ecf20Sopenharmony_ci * if data is appended. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 2978c2ecf20Sopenharmony_ci if (ui->dirty) 2988c2ecf20Sopenharmony_ci /* 2998c2ecf20Sopenharmony_ci * The inode is dirty already, so we may free the 3008c2ecf20Sopenharmony_ci * budget we allocated. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci ubifs_release_dirty_inode_budget(c, ui); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci *pagep = page; 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/** 3108c2ecf20Sopenharmony_ci * allocate_budget - allocate budget for 'ubifs_write_begin()'. 3118c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3128c2ecf20Sopenharmony_ci * @page: page to allocate budget for 3138c2ecf20Sopenharmony_ci * @ui: UBIFS inode object the page belongs to 3148c2ecf20Sopenharmony_ci * @appending: non-zero if the page is appended 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * This is a helper function for 'ubifs_write_begin()' which allocates budget 3178c2ecf20Sopenharmony_ci * for the operation. The budget is allocated differently depending on whether 3188c2ecf20Sopenharmony_ci * this is appending, whether the page is dirty or not, and so on. This 3198c2ecf20Sopenharmony_ci * function leaves the @ui->ui_mutex locked in case of appending. Returns zero 3208c2ecf20Sopenharmony_ci * in case of success and %-ENOSPC in case of failure. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic int allocate_budget(struct ubifs_info *c, struct page *page, 3238c2ecf20Sopenharmony_ci struct ubifs_inode *ui, int appending) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .fast = 1 }; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (PagePrivate(page)) { 3288c2ecf20Sopenharmony_ci if (!appending) 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * The page is dirty and we are not appending, which 3318c2ecf20Sopenharmony_ci * means no budget is needed at all. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 3368c2ecf20Sopenharmony_ci if (ui->dirty) 3378c2ecf20Sopenharmony_ci /* 3388c2ecf20Sopenharmony_ci * The page is dirty and we are appending, so the inode 3398c2ecf20Sopenharmony_ci * has to be marked as dirty. However, it is already 3408c2ecf20Sopenharmony_ci * dirty, so we do not need any budget. We may return, 3418c2ecf20Sopenharmony_ci * but @ui->ui_mutex hast to be left locked because we 3428c2ecf20Sopenharmony_ci * should prevent write-back from flushing the inode 3438c2ecf20Sopenharmony_ci * and freeing the budget. The lock will be released in 3448c2ecf20Sopenharmony_ci * 'ubifs_write_end()'. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * The page is dirty, we are appending, the inode is clean, so 3508c2ecf20Sopenharmony_ci * we need to budget the inode change. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci req.dirtied_ino = 1; 3538c2ecf20Sopenharmony_ci } else { 3548c2ecf20Sopenharmony_ci if (PageChecked(page)) 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * The page corresponds to a hole and does not 3578c2ecf20Sopenharmony_ci * exist on the media. So changing it makes 3588c2ecf20Sopenharmony_ci * make the amount of indexing information 3598c2ecf20Sopenharmony_ci * larger, and we have to budget for a new 3608c2ecf20Sopenharmony_ci * page. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci req.new_page = 1; 3638c2ecf20Sopenharmony_ci else 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Not a hole, the change will not add any new 3668c2ecf20Sopenharmony_ci * indexing information, budget for page 3678c2ecf20Sopenharmony_ci * change. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci req.dirtied_page = 1; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (appending) { 3728c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 3738c2ecf20Sopenharmony_ci if (!ui->dirty) 3748c2ecf20Sopenharmony_ci /* 3758c2ecf20Sopenharmony_ci * The inode is clean but we will have to mark 3768c2ecf20Sopenharmony_ci * it as dirty because we are appending. This 3778c2ecf20Sopenharmony_ci * needs a budget. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci req.dirtied_ino = 1; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return ubifs_budget_space(c, &req); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* 3878c2ecf20Sopenharmony_ci * This function is called when a page of data is going to be written. Since 3888c2ecf20Sopenharmony_ci * the page of data will not necessarily go to the flash straight away, UBIFS 3898c2ecf20Sopenharmony_ci * has to reserve space on the media for it, which is done by means of 3908c2ecf20Sopenharmony_ci * budgeting. 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * This is the hot-path of the file-system and we are trying to optimize it as 3938c2ecf20Sopenharmony_ci * much as possible. For this reasons it is split on 2 parts - slow and fast. 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * There many budgeting cases: 3968c2ecf20Sopenharmony_ci * o a new page is appended - we have to budget for a new page and for 3978c2ecf20Sopenharmony_ci * changing the inode; however, if the inode is already dirty, there is 3988c2ecf20Sopenharmony_ci * no need to budget for it; 3998c2ecf20Sopenharmony_ci * o an existing clean page is changed - we have budget for it; if the page 4008c2ecf20Sopenharmony_ci * does not exist on the media (a hole), we have to budget for a new 4018c2ecf20Sopenharmony_ci * page; otherwise, we may budget for changing an existing page; the 4028c2ecf20Sopenharmony_ci * difference between these cases is that changing an existing page does 4038c2ecf20Sopenharmony_ci * not introduce anything new to the FS indexing information, so it does 4048c2ecf20Sopenharmony_ci * not grow, and smaller budget is acquired in this case; 4058c2ecf20Sopenharmony_ci * o an existing dirty page is changed - no need to budget at all, because 4068c2ecf20Sopenharmony_ci * the page budget has been acquired by earlier, when the page has been 4078c2ecf20Sopenharmony_ci * marked dirty. 4088c2ecf20Sopenharmony_ci * 4098c2ecf20Sopenharmony_ci * UBIFS budgeting sub-system may force write-back if it thinks there is no 4108c2ecf20Sopenharmony_ci * space to reserve. This imposes some locking restrictions and makes it 4118c2ecf20Sopenharmony_ci * impossible to take into account the above cases, and makes it impossible to 4128c2ecf20Sopenharmony_ci * optimize budgeting. 4138c2ecf20Sopenharmony_ci * 4148c2ecf20Sopenharmony_ci * The solution for this is that the fast path of 'ubifs_write_begin()' assumes 4158c2ecf20Sopenharmony_ci * there is a plenty of flash space and the budget will be acquired quickly, 4168c2ecf20Sopenharmony_ci * without forcing write-back. The slow path does not make this assumption. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_cistatic int ubifs_write_begin(struct file *file, struct address_space *mapping, 4198c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 4208c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 4238c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 4248c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 4258c2ecf20Sopenharmony_ci pgoff_t index = pos >> PAGE_SHIFT; 4268c2ecf20Sopenharmony_ci int err, appending = !!(pos + len > inode->i_size); 4278c2ecf20Sopenharmony_ci int skipped_read = 0; 4288c2ecf20Sopenharmony_ci struct page *page; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci ubifs_assert(c, ubifs_inode(inode)->ui_size == inode->i_size); 4318c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (unlikely(c->ro_error)) 4348c2ecf20Sopenharmony_ci return -EROFS; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Try out the fast-path part first */ 4378c2ecf20Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index, flags); 4388c2ecf20Sopenharmony_ci if (unlikely(!page)) 4398c2ecf20Sopenharmony_ci return -ENOMEM; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 4428c2ecf20Sopenharmony_ci /* The page is not loaded from the flash */ 4438c2ecf20Sopenharmony_ci if (!(pos & ~PAGE_MASK) && len == PAGE_SIZE) { 4448c2ecf20Sopenharmony_ci /* 4458c2ecf20Sopenharmony_ci * We change whole page so no need to load it. But we 4468c2ecf20Sopenharmony_ci * do not know whether this page exists on the media or 4478c2ecf20Sopenharmony_ci * not, so we assume the latter because it requires 4488c2ecf20Sopenharmony_ci * larger budget. The assumption is that it is better 4498c2ecf20Sopenharmony_ci * to budget a bit more than to read the page from the 4508c2ecf20Sopenharmony_ci * media. Thus, we are setting the @PG_checked flag 4518c2ecf20Sopenharmony_ci * here. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci SetPageChecked(page); 4548c2ecf20Sopenharmony_ci skipped_read = 1; 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci err = do_readpage(page); 4578c2ecf20Sopenharmony_ci if (err) { 4588c2ecf20Sopenharmony_ci unlock_page(page); 4598c2ecf20Sopenharmony_ci put_page(page); 4608c2ecf20Sopenharmony_ci return err; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci err = allocate_budget(c, page, ui, appending); 4668c2ecf20Sopenharmony_ci if (unlikely(err)) { 4678c2ecf20Sopenharmony_ci ubifs_assert(c, err == -ENOSPC); 4688c2ecf20Sopenharmony_ci /* 4698c2ecf20Sopenharmony_ci * If we skipped reading the page because we were going to 4708c2ecf20Sopenharmony_ci * write all of it, then it is not up to date. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci if (skipped_read) 4738c2ecf20Sopenharmony_ci ClearPageChecked(page); 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * Budgeting failed which means it would have to force 4768c2ecf20Sopenharmony_ci * write-back but didn't, because we set the @fast flag in the 4778c2ecf20Sopenharmony_ci * request. Write-back cannot be done now, while we have the 4788c2ecf20Sopenharmony_ci * page locked, because it would deadlock. Unlock and free 4798c2ecf20Sopenharmony_ci * everything and fall-back to slow-path. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci if (appending) { 4828c2ecf20Sopenharmony_ci ubifs_assert(c, mutex_is_locked(&ui->ui_mutex)); 4838c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci unlock_page(page); 4868c2ecf20Sopenharmony_ci put_page(page); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return write_begin_slow(mapping, pos, len, pagep, flags); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* 4928c2ecf20Sopenharmony_ci * Whee, we acquired budgeting quickly - without involving 4938c2ecf20Sopenharmony_ci * garbage-collection, committing or forcing write-back. We return 4948c2ecf20Sopenharmony_ci * with @ui->ui_mutex locked if we are appending pages, and unlocked 4958c2ecf20Sopenharmony_ci * otherwise. This is an optimization (slightly hacky though). 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci *pagep = page; 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/** 5038c2ecf20Sopenharmony_ci * cancel_budget - cancel budget. 5048c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5058c2ecf20Sopenharmony_ci * @page: page to cancel budget for 5068c2ecf20Sopenharmony_ci * @ui: UBIFS inode object the page belongs to 5078c2ecf20Sopenharmony_ci * @appending: non-zero if the page is appended 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * This is a helper function for a page write operation. It unlocks the 5108c2ecf20Sopenharmony_ci * @ui->ui_mutex in case of appending. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic void cancel_budget(struct ubifs_info *c, struct page *page, 5138c2ecf20Sopenharmony_ci struct ubifs_inode *ui, int appending) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci if (appending) { 5168c2ecf20Sopenharmony_ci if (!ui->dirty) 5178c2ecf20Sopenharmony_ci ubifs_release_dirty_inode_budget(c, ui); 5188c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci if (!PagePrivate(page)) { 5218c2ecf20Sopenharmony_ci if (PageChecked(page)) 5228c2ecf20Sopenharmony_ci release_new_page_budget(c); 5238c2ecf20Sopenharmony_ci else 5248c2ecf20Sopenharmony_ci release_existing_page_budget(c); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int ubifs_write_end(struct file *file, struct address_space *mapping, 5298c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 5308c2ecf20Sopenharmony_ci struct page *page, void *fsdata) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 5338c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 5348c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 5358c2ecf20Sopenharmony_ci loff_t end_pos = pos + len; 5368c2ecf20Sopenharmony_ci int appending = !!(end_pos > inode->i_size); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld", 5398c2ecf20Sopenharmony_ci inode->i_ino, pos, page->index, len, copied, inode->i_size); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (unlikely(copied < len && len == PAGE_SIZE)) { 5428c2ecf20Sopenharmony_ci /* 5438c2ecf20Sopenharmony_ci * VFS copied less data to the page that it intended and 5448c2ecf20Sopenharmony_ci * declared in its '->write_begin()' call via the @len 5458c2ecf20Sopenharmony_ci * argument. If the page was not up-to-date, and @len was 5468c2ecf20Sopenharmony_ci * @PAGE_SIZE, the 'ubifs_write_begin()' function did 5478c2ecf20Sopenharmony_ci * not load it from the media (for optimization reasons). This 5488c2ecf20Sopenharmony_ci * means that part of the page contains garbage. So read the 5498c2ecf20Sopenharmony_ci * page now. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci dbg_gen("copied %d instead of %d, read page and repeat", 5528c2ecf20Sopenharmony_ci copied, len); 5538c2ecf20Sopenharmony_ci cancel_budget(c, page, ui, appending); 5548c2ecf20Sopenharmony_ci ClearPageChecked(page); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * Return 0 to force VFS to repeat the whole operation, or the 5588c2ecf20Sopenharmony_ci * error code if 'do_readpage()' fails. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci copied = do_readpage(page); 5618c2ecf20Sopenharmony_ci goto out; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (len == PAGE_SIZE) 5658c2ecf20Sopenharmony_ci SetPageUptodate(page); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (!PagePrivate(page)) { 5688c2ecf20Sopenharmony_ci attach_page_private(page, (void *)1); 5698c2ecf20Sopenharmony_ci atomic_long_inc(&c->dirty_pg_cnt); 5708c2ecf20Sopenharmony_ci __set_page_dirty_nobuffers(page); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (appending) { 5748c2ecf20Sopenharmony_ci i_size_write(inode, end_pos); 5758c2ecf20Sopenharmony_ci ui->ui_size = end_pos; 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * Note, we do not set @I_DIRTY_PAGES (which means that the 5788c2ecf20Sopenharmony_ci * inode has dirty pages), this has been done in 5798c2ecf20Sopenharmony_ci * '__set_page_dirty_nobuffers()'. 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 5828c2ecf20Sopenharmony_ci ubifs_assert(c, mutex_is_locked(&ui->ui_mutex)); 5838c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ciout: 5878c2ecf20Sopenharmony_ci unlock_page(page); 5888c2ecf20Sopenharmony_ci put_page(page); 5898c2ecf20Sopenharmony_ci return copied; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/** 5938c2ecf20Sopenharmony_ci * populate_page - copy data nodes into a page for bulk-read. 5948c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5958c2ecf20Sopenharmony_ci * @page: page 5968c2ecf20Sopenharmony_ci * @bu: bulk-read information 5978c2ecf20Sopenharmony_ci * @n: next zbranch slot 5988c2ecf20Sopenharmony_ci * 5998c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 6008c2ecf20Sopenharmony_ci */ 6018c2ecf20Sopenharmony_cistatic int populate_page(struct ubifs_info *c, struct page *page, 6028c2ecf20Sopenharmony_ci struct bu_info *bu, int *n) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci int i = 0, nn = *n, offs = bu->zbranch[0].offs, hole = 0, read = 0; 6058c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 6068c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(inode); 6078c2ecf20Sopenharmony_ci unsigned int page_block; 6088c2ecf20Sopenharmony_ci void *addr, *zaddr; 6098c2ecf20Sopenharmony_ci pgoff_t end_index; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx", 6128c2ecf20Sopenharmony_ci inode->i_ino, page->index, i_size, page->flags); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci addr = zaddr = kmap(page); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci end_index = (i_size - 1) >> PAGE_SHIFT; 6178c2ecf20Sopenharmony_ci if (!i_size || page->index > end_index) { 6188c2ecf20Sopenharmony_ci hole = 1; 6198c2ecf20Sopenharmony_ci memset(addr, 0, PAGE_SIZE); 6208c2ecf20Sopenharmony_ci goto out_hole; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci page_block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; 6248c2ecf20Sopenharmony_ci while (1) { 6258c2ecf20Sopenharmony_ci int err, len, out_len, dlen; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (nn >= bu->cnt) { 6288c2ecf20Sopenharmony_ci hole = 1; 6298c2ecf20Sopenharmony_ci memset(addr, 0, UBIFS_BLOCK_SIZE); 6308c2ecf20Sopenharmony_ci } else if (key_block(c, &bu->zbranch[nn].key) == page_block) { 6318c2ecf20Sopenharmony_ci struct ubifs_data_node *dn; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dn = bu->buf + (bu->zbranch[nn].offs - offs); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci ubifs_assert(c, le64_to_cpu(dn->ch.sqnum) > 6368c2ecf20Sopenharmony_ci ubifs_inode(inode)->creat_sqnum); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci len = le32_to_cpu(dn->size); 6398c2ecf20Sopenharmony_ci if (len <= 0 || len > UBIFS_BLOCK_SIZE) 6408c2ecf20Sopenharmony_ci goto out_err; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; 6438c2ecf20Sopenharmony_ci out_len = UBIFS_BLOCK_SIZE; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(inode)) { 6468c2ecf20Sopenharmony_ci err = ubifs_decrypt(inode, dn, &dlen, page_block); 6478c2ecf20Sopenharmony_ci if (err) 6488c2ecf20Sopenharmony_ci goto out_err; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len, 6528c2ecf20Sopenharmony_ci le16_to_cpu(dn->compr_type)); 6538c2ecf20Sopenharmony_ci if (err || len != out_len) 6548c2ecf20Sopenharmony_ci goto out_err; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (len < UBIFS_BLOCK_SIZE) 6578c2ecf20Sopenharmony_ci memset(addr + len, 0, UBIFS_BLOCK_SIZE - len); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci nn += 1; 6608c2ecf20Sopenharmony_ci read = (i << UBIFS_BLOCK_SHIFT) + len; 6618c2ecf20Sopenharmony_ci } else if (key_block(c, &bu->zbranch[nn].key) < page_block) { 6628c2ecf20Sopenharmony_ci nn += 1; 6638c2ecf20Sopenharmony_ci continue; 6648c2ecf20Sopenharmony_ci } else { 6658c2ecf20Sopenharmony_ci hole = 1; 6668c2ecf20Sopenharmony_ci memset(addr, 0, UBIFS_BLOCK_SIZE); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if (++i >= UBIFS_BLOCKS_PER_PAGE) 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci addr += UBIFS_BLOCK_SIZE; 6718c2ecf20Sopenharmony_ci page_block += 1; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (end_index == page->index) { 6758c2ecf20Sopenharmony_ci int len = i_size & (PAGE_SIZE - 1); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (len && len < read) 6788c2ecf20Sopenharmony_ci memset(zaddr + len, 0, read - len); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ciout_hole: 6828c2ecf20Sopenharmony_ci if (hole) { 6838c2ecf20Sopenharmony_ci SetPageChecked(page); 6848c2ecf20Sopenharmony_ci dbg_gen("hole"); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci SetPageUptodate(page); 6888c2ecf20Sopenharmony_ci ClearPageError(page); 6898c2ecf20Sopenharmony_ci flush_dcache_page(page); 6908c2ecf20Sopenharmony_ci kunmap(page); 6918c2ecf20Sopenharmony_ci *n = nn; 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ciout_err: 6958c2ecf20Sopenharmony_ci ClearPageUptodate(page); 6968c2ecf20Sopenharmony_ci SetPageError(page); 6978c2ecf20Sopenharmony_ci flush_dcache_page(page); 6988c2ecf20Sopenharmony_ci kunmap(page); 6998c2ecf20Sopenharmony_ci ubifs_err(c, "bad data node (block %u, inode %lu)", 7008c2ecf20Sopenharmony_ci page_block, inode->i_ino); 7018c2ecf20Sopenharmony_ci return -EINVAL; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci/** 7058c2ecf20Sopenharmony_ci * ubifs_do_bulk_read - do bulk-read. 7068c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 7078c2ecf20Sopenharmony_ci * @bu: bulk-read information 7088c2ecf20Sopenharmony_ci * @page1: first page to read 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci * This function returns %1 if the bulk-read is done, otherwise %0 is returned. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_cistatic int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, 7138c2ecf20Sopenharmony_ci struct page *page1) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci pgoff_t offset = page1->index, end_index; 7168c2ecf20Sopenharmony_ci struct address_space *mapping = page1->mapping; 7178c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 7188c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 7198c2ecf20Sopenharmony_ci int err, page_idx, page_cnt, ret = 0, n = 0; 7208c2ecf20Sopenharmony_ci int allocate = bu->buf ? 0 : 1; 7218c2ecf20Sopenharmony_ci loff_t isize; 7228c2ecf20Sopenharmony_ci gfp_t ra_gfp_mask = readahead_gfp_mask(mapping) & ~__GFP_FS; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci err = ubifs_tnc_get_bu_keys(c, bu); 7258c2ecf20Sopenharmony_ci if (err) 7268c2ecf20Sopenharmony_ci goto out_warn; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (bu->eof) { 7298c2ecf20Sopenharmony_ci /* Turn off bulk-read at the end of the file */ 7308c2ecf20Sopenharmony_ci ui->read_in_a_row = 1; 7318c2ecf20Sopenharmony_ci ui->bulk_read = 0; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci page_cnt = bu->blk_cnt >> UBIFS_BLOCKS_PER_PAGE_SHIFT; 7358c2ecf20Sopenharmony_ci if (!page_cnt) { 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * This happens when there are multiple blocks per page and the 7388c2ecf20Sopenharmony_ci * blocks for the first page we are looking for, are not 7398c2ecf20Sopenharmony_ci * together. If all the pages were like this, bulk-read would 7408c2ecf20Sopenharmony_ci * reduce performance, so we turn it off for a while. 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci goto out_bu_off; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (bu->cnt) { 7468c2ecf20Sopenharmony_ci if (allocate) { 7478c2ecf20Sopenharmony_ci /* 7488c2ecf20Sopenharmony_ci * Allocate bulk-read buffer depending on how many data 7498c2ecf20Sopenharmony_ci * nodes we are going to read. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci bu->buf_len = bu->zbranch[bu->cnt - 1].offs + 7528c2ecf20Sopenharmony_ci bu->zbranch[bu->cnt - 1].len - 7538c2ecf20Sopenharmony_ci bu->zbranch[0].offs; 7548c2ecf20Sopenharmony_ci ubifs_assert(c, bu->buf_len > 0); 7558c2ecf20Sopenharmony_ci ubifs_assert(c, bu->buf_len <= c->leb_size); 7568c2ecf20Sopenharmony_ci bu->buf = kmalloc(bu->buf_len, GFP_NOFS | __GFP_NOWARN); 7578c2ecf20Sopenharmony_ci if (!bu->buf) 7588c2ecf20Sopenharmony_ci goto out_bu_off; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci err = ubifs_tnc_bulk_read(c, bu); 7628c2ecf20Sopenharmony_ci if (err) 7638c2ecf20Sopenharmony_ci goto out_warn; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci err = populate_page(c, page1, bu, &n); 7678c2ecf20Sopenharmony_ci if (err) 7688c2ecf20Sopenharmony_ci goto out_warn; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci unlock_page(page1); 7718c2ecf20Sopenharmony_ci ret = 1; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci isize = i_size_read(inode); 7748c2ecf20Sopenharmony_ci if (isize == 0) 7758c2ecf20Sopenharmony_ci goto out_free; 7768c2ecf20Sopenharmony_ci end_index = ((isize - 1) >> PAGE_SHIFT); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci for (page_idx = 1; page_idx < page_cnt; page_idx++) { 7798c2ecf20Sopenharmony_ci pgoff_t page_offset = offset + page_idx; 7808c2ecf20Sopenharmony_ci struct page *page; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (page_offset > end_index) 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci page = pagecache_get_page(mapping, page_offset, 7858c2ecf20Sopenharmony_ci FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT, 7868c2ecf20Sopenharmony_ci ra_gfp_mask); 7878c2ecf20Sopenharmony_ci if (!page) 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci if (!PageUptodate(page)) 7908c2ecf20Sopenharmony_ci err = populate_page(c, page, bu, &n); 7918c2ecf20Sopenharmony_ci unlock_page(page); 7928c2ecf20Sopenharmony_ci put_page(page); 7938c2ecf20Sopenharmony_ci if (err) 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ui->last_page_read = offset + page_idx - 1; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ciout_free: 8008c2ecf20Sopenharmony_ci if (allocate) 8018c2ecf20Sopenharmony_ci kfree(bu->buf); 8028c2ecf20Sopenharmony_ci return ret; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ciout_warn: 8058c2ecf20Sopenharmony_ci ubifs_warn(c, "ignoring error %d and skipping bulk-read", err); 8068c2ecf20Sopenharmony_ci goto out_free; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ciout_bu_off: 8098c2ecf20Sopenharmony_ci ui->read_in_a_row = ui->bulk_read = 0; 8108c2ecf20Sopenharmony_ci goto out_free; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci/** 8148c2ecf20Sopenharmony_ci * ubifs_bulk_read - determine whether to bulk-read and, if so, do it. 8158c2ecf20Sopenharmony_ci * @page: page from which to start bulk-read. 8168c2ecf20Sopenharmony_ci * 8178c2ecf20Sopenharmony_ci * Some flash media are capable of reading sequentially at faster rates. UBIFS 8188c2ecf20Sopenharmony_ci * bulk-read facility is designed to take advantage of that, by reading in one 8198c2ecf20Sopenharmony_ci * go consecutive data nodes that are also located consecutively in the same 8208c2ecf20Sopenharmony_ci * LEB. This function returns %1 if a bulk-read is done and %0 otherwise. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_cistatic int ubifs_bulk_read(struct page *page) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 8258c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 8268c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 8278c2ecf20Sopenharmony_ci pgoff_t index = page->index, last_page_read = ui->last_page_read; 8288c2ecf20Sopenharmony_ci struct bu_info *bu; 8298c2ecf20Sopenharmony_ci int err = 0, allocated = 0; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ui->last_page_read = index; 8328c2ecf20Sopenharmony_ci if (!c->bulk_read) 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * Bulk-read is protected by @ui->ui_mutex, but it is an optimization, 8378c2ecf20Sopenharmony_ci * so don't bother if we cannot lock the mutex. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci if (!mutex_trylock(&ui->ui_mutex)) 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (index != last_page_read + 1) { 8438c2ecf20Sopenharmony_ci /* Turn off bulk-read if we stop reading sequentially */ 8448c2ecf20Sopenharmony_ci ui->read_in_a_row = 1; 8458c2ecf20Sopenharmony_ci if (ui->bulk_read) 8468c2ecf20Sopenharmony_ci ui->bulk_read = 0; 8478c2ecf20Sopenharmony_ci goto out_unlock; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (!ui->bulk_read) { 8518c2ecf20Sopenharmony_ci ui->read_in_a_row += 1; 8528c2ecf20Sopenharmony_ci if (ui->read_in_a_row < 3) 8538c2ecf20Sopenharmony_ci goto out_unlock; 8548c2ecf20Sopenharmony_ci /* Three reads in a row, so switch on bulk-read */ 8558c2ecf20Sopenharmony_ci ui->bulk_read = 1; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* 8598c2ecf20Sopenharmony_ci * If possible, try to use pre-allocated bulk-read information, which 8608c2ecf20Sopenharmony_ci * is protected by @c->bu_mutex. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci if (mutex_trylock(&c->bu_mutex)) 8638c2ecf20Sopenharmony_ci bu = &c->bu; 8648c2ecf20Sopenharmony_ci else { 8658c2ecf20Sopenharmony_ci bu = kmalloc(sizeof(struct bu_info), GFP_NOFS | __GFP_NOWARN); 8668c2ecf20Sopenharmony_ci if (!bu) 8678c2ecf20Sopenharmony_ci goto out_unlock; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci bu->buf = NULL; 8708c2ecf20Sopenharmony_ci allocated = 1; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci bu->buf_len = c->max_bu_buf_len; 8748c2ecf20Sopenharmony_ci data_key_init(c, &bu->key, inode->i_ino, 8758c2ecf20Sopenharmony_ci page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT); 8768c2ecf20Sopenharmony_ci err = ubifs_do_bulk_read(c, bu, page); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (!allocated) 8798c2ecf20Sopenharmony_ci mutex_unlock(&c->bu_mutex); 8808c2ecf20Sopenharmony_ci else 8818c2ecf20Sopenharmony_ci kfree(bu); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ciout_unlock: 8848c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 8858c2ecf20Sopenharmony_ci return err; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int ubifs_readpage(struct file *file, struct page *page) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci if (ubifs_bulk_read(page)) 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci do_readpage(page); 8938c2ecf20Sopenharmony_ci unlock_page(page); 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int do_writepage(struct page *page, int len) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci int err = 0, i, blen; 9008c2ecf20Sopenharmony_ci unsigned int block; 9018c2ecf20Sopenharmony_ci void *addr; 9028c2ecf20Sopenharmony_ci union ubifs_key key; 9038c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 9048c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci#ifdef UBIFS_DEBUG 9078c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 9088c2ecf20Sopenharmony_ci spin_lock(&ui->ui_lock); 9098c2ecf20Sopenharmony_ci ubifs_assert(c, page->index <= ui->synced_i_size >> PAGE_SHIFT); 9108c2ecf20Sopenharmony_ci spin_unlock(&ui->ui_lock); 9118c2ecf20Sopenharmony_ci#endif 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Update radix tree tags */ 9148c2ecf20Sopenharmony_ci set_page_writeback(page); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci addr = kmap(page); 9178c2ecf20Sopenharmony_ci block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; 9188c2ecf20Sopenharmony_ci i = 0; 9198c2ecf20Sopenharmony_ci while (len) { 9208c2ecf20Sopenharmony_ci blen = min_t(int, len, UBIFS_BLOCK_SIZE); 9218c2ecf20Sopenharmony_ci data_key_init(c, &key, inode->i_ino, block); 9228c2ecf20Sopenharmony_ci err = ubifs_jnl_write_data(c, inode, &key, addr, blen); 9238c2ecf20Sopenharmony_ci if (err) 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci if (++i >= UBIFS_BLOCKS_PER_PAGE) 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci block += 1; 9288c2ecf20Sopenharmony_ci addr += blen; 9298c2ecf20Sopenharmony_ci len -= blen; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci if (err) { 9328c2ecf20Sopenharmony_ci SetPageError(page); 9338c2ecf20Sopenharmony_ci ubifs_err(c, "cannot write page %lu of inode %lu, error %d", 9348c2ecf20Sopenharmony_ci page->index, inode->i_ino, err); 9358c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci ubifs_assert(c, PagePrivate(page)); 9398c2ecf20Sopenharmony_ci if (PageChecked(page)) 9408c2ecf20Sopenharmony_ci release_new_page_budget(c); 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci release_existing_page_budget(c); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci atomic_long_dec(&c->dirty_pg_cnt); 9458c2ecf20Sopenharmony_ci detach_page_private(page); 9468c2ecf20Sopenharmony_ci ClearPageChecked(page); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci kunmap(page); 9498c2ecf20Sopenharmony_ci unlock_page(page); 9508c2ecf20Sopenharmony_ci end_page_writeback(page); 9518c2ecf20Sopenharmony_ci return err; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci/* 9558c2ecf20Sopenharmony_ci * When writing-back dirty inodes, VFS first writes-back pages belonging to the 9568c2ecf20Sopenharmony_ci * inode, then the inode itself. For UBIFS this may cause a problem. Consider a 9578c2ecf20Sopenharmony_ci * situation when a we have an inode with size 0, then a megabyte of data is 9588c2ecf20Sopenharmony_ci * appended to the inode, then write-back starts and flushes some amount of the 9598c2ecf20Sopenharmony_ci * dirty pages, the journal becomes full, commit happens and finishes, and then 9608c2ecf20Sopenharmony_ci * an unclean reboot happens. When the file system is mounted next time, the 9618c2ecf20Sopenharmony_ci * inode size would still be 0, but there would be many pages which are beyond 9628c2ecf20Sopenharmony_ci * the inode size, they would be indexed and consume flash space. Because the 9638c2ecf20Sopenharmony_ci * journal has been committed, the replay would not be able to detect this 9648c2ecf20Sopenharmony_ci * situation and correct the inode size. This means UBIFS would have to scan 9658c2ecf20Sopenharmony_ci * whole index and correct all inode sizes, which is long an unacceptable. 9668c2ecf20Sopenharmony_ci * 9678c2ecf20Sopenharmony_ci * To prevent situations like this, UBIFS writes pages back only if they are 9688c2ecf20Sopenharmony_ci * within the last synchronized inode size, i.e. the size which has been 9698c2ecf20Sopenharmony_ci * written to the flash media last time. Otherwise, UBIFS forces inode 9708c2ecf20Sopenharmony_ci * write-back, thus making sure the on-flash inode contains current inode size, 9718c2ecf20Sopenharmony_ci * and then keeps writing pages back. 9728c2ecf20Sopenharmony_ci * 9738c2ecf20Sopenharmony_ci * Some locking issues explanation. 'ubifs_writepage()' first is called with 9748c2ecf20Sopenharmony_ci * the page locked, and it locks @ui_mutex. However, write-back does take inode 9758c2ecf20Sopenharmony_ci * @i_mutex, which means other VFS operations may be run on this inode at the 9768c2ecf20Sopenharmony_ci * same time. And the problematic one is truncation to smaller size, from where 9778c2ecf20Sopenharmony_ci * we have to call 'truncate_setsize()', which first changes @inode->i_size, 9788c2ecf20Sopenharmony_ci * then drops the truncated pages. And while dropping the pages, it takes the 9798c2ecf20Sopenharmony_ci * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' 9808c2ecf20Sopenharmony_ci * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. 9818c2ecf20Sopenharmony_ci * This means that @inode->i_size is changed while @ui_mutex is unlocked. 9828c2ecf20Sopenharmony_ci * 9838c2ecf20Sopenharmony_ci * XXX(truncate): with the new truncate sequence this is not true anymore, 9848c2ecf20Sopenharmony_ci * and the calls to truncate_setsize can be move around freely. They should 9858c2ecf20Sopenharmony_ci * be moved to the very end of the truncate sequence. 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * But in 'ubifs_writepage()' we have to guarantee that we do not write beyond 9888c2ecf20Sopenharmony_ci * inode size. How do we do this if @inode->i_size may became smaller while we 9898c2ecf20Sopenharmony_ci * are in the middle of 'ubifs_writepage()'? The UBIFS solution is the 9908c2ecf20Sopenharmony_ci * @ui->ui_isize "shadow" field which UBIFS uses instead of @inode->i_size 9918c2ecf20Sopenharmony_ci * internally and updates it under @ui_mutex. 9928c2ecf20Sopenharmony_ci * 9938c2ecf20Sopenharmony_ci * Q: why we do not worry that if we race with truncation, we may end up with a 9948c2ecf20Sopenharmony_ci * situation when the inode is truncated while we are in the middle of 9958c2ecf20Sopenharmony_ci * 'do_writepage()', so we do write beyond inode size? 9968c2ecf20Sopenharmony_ci * A: If we are in the middle of 'do_writepage()', truncation would be locked 9978c2ecf20Sopenharmony_ci * on the page lock and it would not write the truncated inode node to the 9988c2ecf20Sopenharmony_ci * journal before we have finished. 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_cistatic int ubifs_writepage(struct page *page, struct writeback_control *wbc) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 10038c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 10048c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 10058c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(inode), synced_i_size; 10068c2ecf20Sopenharmony_ci pgoff_t end_index = i_size >> PAGE_SHIFT; 10078c2ecf20Sopenharmony_ci int err, len = i_size & (PAGE_SIZE - 1); 10088c2ecf20Sopenharmony_ci void *kaddr; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pg %lu, pg flags %#lx", 10118c2ecf20Sopenharmony_ci inode->i_ino, page->index, page->flags); 10128c2ecf20Sopenharmony_ci ubifs_assert(c, PagePrivate(page)); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Is the page fully outside @i_size? (truncate in progress) */ 10158c2ecf20Sopenharmony_ci if (page->index > end_index || (page->index == end_index && !len)) { 10168c2ecf20Sopenharmony_ci err = 0; 10178c2ecf20Sopenharmony_ci goto out_unlock; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci spin_lock(&ui->ui_lock); 10218c2ecf20Sopenharmony_ci synced_i_size = ui->synced_i_size; 10228c2ecf20Sopenharmony_ci spin_unlock(&ui->ui_lock); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* Is the page fully inside @i_size? */ 10258c2ecf20Sopenharmony_ci if (page->index < end_index) { 10268c2ecf20Sopenharmony_ci if (page->index >= synced_i_size >> PAGE_SHIFT) { 10278c2ecf20Sopenharmony_ci err = inode->i_sb->s_op->write_inode(inode, NULL); 10288c2ecf20Sopenharmony_ci if (err) 10298c2ecf20Sopenharmony_ci goto out_redirty; 10308c2ecf20Sopenharmony_ci /* 10318c2ecf20Sopenharmony_ci * The inode has been written, but the write-buffer has 10328c2ecf20Sopenharmony_ci * not been synchronized, so in case of an unclean 10338c2ecf20Sopenharmony_ci * reboot we may end up with some pages beyond inode 10348c2ecf20Sopenharmony_ci * size, but they would be in the journal (because 10358c2ecf20Sopenharmony_ci * commit flushes write buffers) and recovery would deal 10368c2ecf20Sopenharmony_ci * with this. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci return do_writepage(page, PAGE_SIZE); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* 10438c2ecf20Sopenharmony_ci * The page straddles @i_size. It must be zeroed out on each and every 10448c2ecf20Sopenharmony_ci * writepage invocation because it may be mmapped. "A file is mapped 10458c2ecf20Sopenharmony_ci * in multiples of the page size. For a file that is not a multiple of 10468c2ecf20Sopenharmony_ci * the page size, the remaining memory is zeroed when mapped, and 10478c2ecf20Sopenharmony_ci * writes to that region are not written out to the file." 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci kaddr = kmap_atomic(page); 10508c2ecf20Sopenharmony_ci memset(kaddr + len, 0, PAGE_SIZE - len); 10518c2ecf20Sopenharmony_ci flush_dcache_page(page); 10528c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (i_size > synced_i_size) { 10558c2ecf20Sopenharmony_ci err = inode->i_sb->s_op->write_inode(inode, NULL); 10568c2ecf20Sopenharmony_ci if (err) 10578c2ecf20Sopenharmony_ci goto out_redirty; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci return do_writepage(page, len); 10618c2ecf20Sopenharmony_ciout_redirty: 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * redirty_page_for_writepage() won't call ubifs_dirty_inode() because 10648c2ecf20Sopenharmony_ci * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so 10658c2ecf20Sopenharmony_ci * there is no need to do space budget for dirty inode. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, page); 10688c2ecf20Sopenharmony_ciout_unlock: 10698c2ecf20Sopenharmony_ci unlock_page(page); 10708c2ecf20Sopenharmony_ci return err; 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci/** 10748c2ecf20Sopenharmony_ci * do_attr_changes - change inode attributes. 10758c2ecf20Sopenharmony_ci * @inode: inode to change attributes for 10768c2ecf20Sopenharmony_ci * @attr: describes attributes to change 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_cistatic void do_attr_changes(struct inode *inode, const struct iattr *attr) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_UID) 10818c2ecf20Sopenharmony_ci inode->i_uid = attr->ia_uid; 10828c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_GID) 10838c2ecf20Sopenharmony_ci inode->i_gid = attr->ia_gid; 10848c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_ATIME) 10858c2ecf20Sopenharmony_ci inode->i_atime = attr->ia_atime; 10868c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_MTIME) 10878c2ecf20Sopenharmony_ci inode->i_mtime = attr->ia_mtime; 10888c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_CTIME) 10898c2ecf20Sopenharmony_ci inode->i_ctime = attr->ia_ctime; 10908c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_MODE) { 10918c2ecf20Sopenharmony_ci umode_t mode = attr->ia_mode; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) 10948c2ecf20Sopenharmony_ci mode &= ~S_ISGID; 10958c2ecf20Sopenharmony_ci inode->i_mode = mode; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/** 11008c2ecf20Sopenharmony_ci * do_truncation - truncate an inode. 11018c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 11028c2ecf20Sopenharmony_ci * @inode: inode to truncate 11038c2ecf20Sopenharmony_ci * @attr: inode attribute changes description 11048c2ecf20Sopenharmony_ci * 11058c2ecf20Sopenharmony_ci * This function implements VFS '->setattr()' call when the inode is truncated 11068c2ecf20Sopenharmony_ci * to a smaller size. Returns zero in case of success and a negative error code 11078c2ecf20Sopenharmony_ci * in case of failure. 11088c2ecf20Sopenharmony_ci */ 11098c2ecf20Sopenharmony_cistatic int do_truncation(struct ubifs_info *c, struct inode *inode, 11108c2ecf20Sopenharmony_ci const struct iattr *attr) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci int err; 11138c2ecf20Sopenharmony_ci struct ubifs_budget_req req; 11148c2ecf20Sopenharmony_ci loff_t old_size = inode->i_size, new_size = attr->ia_size; 11158c2ecf20Sopenharmony_ci int offset = new_size & (UBIFS_BLOCK_SIZE - 1), budgeted = 1; 11168c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci dbg_gen("ino %lu, size %lld -> %lld", inode->i_ino, old_size, new_size); 11198c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(struct ubifs_budget_req)); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* 11228c2ecf20Sopenharmony_ci * If this is truncation to a smaller size, and we do not truncate on a 11238c2ecf20Sopenharmony_ci * block boundary, budget for changing one data block, because the last 11248c2ecf20Sopenharmony_ci * block will be re-written. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci if (new_size & (UBIFS_BLOCK_SIZE - 1)) 11278c2ecf20Sopenharmony_ci req.dirtied_page = 1; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci req.dirtied_ino = 1; 11308c2ecf20Sopenharmony_ci /* A funny way to budget for truncation node */ 11318c2ecf20Sopenharmony_ci req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ; 11328c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 11338c2ecf20Sopenharmony_ci if (err) { 11348c2ecf20Sopenharmony_ci /* 11358c2ecf20Sopenharmony_ci * Treat truncations to zero as deletion and always allow them, 11368c2ecf20Sopenharmony_ci * just like we do for '->unlink()'. 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_ci if (new_size || err != -ENOSPC) 11398c2ecf20Sopenharmony_ci return err; 11408c2ecf20Sopenharmony_ci budgeted = 0; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci truncate_setsize(inode, new_size); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (offset) { 11468c2ecf20Sopenharmony_ci pgoff_t index = new_size >> PAGE_SHIFT; 11478c2ecf20Sopenharmony_ci struct page *page; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci page = find_lock_page(inode->i_mapping, index); 11508c2ecf20Sopenharmony_ci if (page) { 11518c2ecf20Sopenharmony_ci if (PageDirty(page)) { 11528c2ecf20Sopenharmony_ci /* 11538c2ecf20Sopenharmony_ci * 'ubifs_jnl_truncate()' will try to truncate 11548c2ecf20Sopenharmony_ci * the last data node, but it contains 11558c2ecf20Sopenharmony_ci * out-of-date data because the page is dirty. 11568c2ecf20Sopenharmony_ci * Write the page now, so that 11578c2ecf20Sopenharmony_ci * 'ubifs_jnl_truncate()' will see an already 11588c2ecf20Sopenharmony_ci * truncated (and up to date) data node. 11598c2ecf20Sopenharmony_ci */ 11608c2ecf20Sopenharmony_ci ubifs_assert(c, PagePrivate(page)); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci clear_page_dirty_for_io(page); 11638c2ecf20Sopenharmony_ci if (UBIFS_BLOCKS_PER_PAGE_SHIFT) 11648c2ecf20Sopenharmony_ci offset = new_size & 11658c2ecf20Sopenharmony_ci (PAGE_SIZE - 1); 11668c2ecf20Sopenharmony_ci err = do_writepage(page, offset); 11678c2ecf20Sopenharmony_ci put_page(page); 11688c2ecf20Sopenharmony_ci if (err) 11698c2ecf20Sopenharmony_ci goto out_budg; 11708c2ecf20Sopenharmony_ci /* 11718c2ecf20Sopenharmony_ci * We could now tell 'ubifs_jnl_truncate()' not 11728c2ecf20Sopenharmony_ci * to read the last block. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci /* 11768c2ecf20Sopenharmony_ci * We could 'kmap()' the page and pass the data 11778c2ecf20Sopenharmony_ci * to 'ubifs_jnl_truncate()' to save it from 11788c2ecf20Sopenharmony_ci * having to read it. 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_ci unlock_page(page); 11818c2ecf20Sopenharmony_ci put_page(page); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 11878c2ecf20Sopenharmony_ci ui->ui_size = inode->i_size; 11888c2ecf20Sopenharmony_ci /* Truncation changes inode [mc]time */ 11898c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 11908c2ecf20Sopenharmony_ci /* Other attributes may be changed at the same time as well */ 11918c2ecf20Sopenharmony_ci do_attr_changes(inode, attr); 11928c2ecf20Sopenharmony_ci err = ubifs_jnl_truncate(c, inode, old_size, new_size); 11938c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ciout_budg: 11968c2ecf20Sopenharmony_ci if (budgeted) 11978c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 11988c2ecf20Sopenharmony_ci else { 11998c2ecf20Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 12008c2ecf20Sopenharmony_ci smp_wmb(); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci return err; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/** 12068c2ecf20Sopenharmony_ci * do_setattr - change inode attributes. 12078c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 12088c2ecf20Sopenharmony_ci * @inode: inode to change attributes for 12098c2ecf20Sopenharmony_ci * @attr: inode attribute changes description 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * This function implements VFS '->setattr()' call for all cases except 12128c2ecf20Sopenharmony_ci * truncations to smaller size. Returns zero in case of success and a negative 12138c2ecf20Sopenharmony_ci * error code in case of failure. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_cistatic int do_setattr(struct ubifs_info *c, struct inode *inode, 12168c2ecf20Sopenharmony_ci const struct iattr *attr) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci int err, release; 12198c2ecf20Sopenharmony_ci loff_t new_size = attr->ia_size; 12208c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 12218c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .dirtied_ino = 1, 12228c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 12258c2ecf20Sopenharmony_ci if (err) 12268c2ecf20Sopenharmony_ci return err; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) { 12298c2ecf20Sopenharmony_ci dbg_gen("size %lld -> %lld", inode->i_size, new_size); 12308c2ecf20Sopenharmony_ci truncate_setsize(inode, new_size); 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 12348c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) { 12358c2ecf20Sopenharmony_ci /* Truncation changes inode [mc]time */ 12368c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 12378c2ecf20Sopenharmony_ci /* 'truncate_setsize()' changed @i_size, update @ui_size */ 12388c2ecf20Sopenharmony_ci ui->ui_size = inode->i_size; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci do_attr_changes(inode, attr); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci release = ui->dirty; 12448c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * Inode length changed, so we have to make sure 12478c2ecf20Sopenharmony_ci * @I_DIRTY_DATASYNC is set. 12488c2ecf20Sopenharmony_ci */ 12498c2ecf20Sopenharmony_ci __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 12508c2ecf20Sopenharmony_ci else 12518c2ecf20Sopenharmony_ci mark_inode_dirty_sync(inode); 12528c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (release) 12558c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 12568c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 12578c2ecf20Sopenharmony_ci err = inode->i_sb->s_op->write_inode(inode, NULL); 12588c2ecf20Sopenharmony_ci return err; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ciint ubifs_setattr(struct dentry *dentry, struct iattr *attr) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci int err; 12648c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 12658c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci dbg_gen("ino %lu, mode %#x, ia_valid %#x", 12688c2ecf20Sopenharmony_ci inode->i_ino, inode->i_mode, attr->ia_valid); 12698c2ecf20Sopenharmony_ci err = setattr_prepare(dentry, attr); 12708c2ecf20Sopenharmony_ci if (err) 12718c2ecf20Sopenharmony_ci return err; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci err = dbg_check_synced_i_size(c, inode); 12748c2ecf20Sopenharmony_ci if (err) 12758c2ecf20Sopenharmony_ci return err; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci err = fscrypt_prepare_setattr(dentry, attr); 12788c2ecf20Sopenharmony_ci if (err) 12798c2ecf20Sopenharmony_ci return err; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size) 12828c2ecf20Sopenharmony_ci /* Truncation to a smaller size */ 12838c2ecf20Sopenharmony_ci err = do_truncation(c, inode, attr); 12848c2ecf20Sopenharmony_ci else 12858c2ecf20Sopenharmony_ci err = do_setattr(c, inode, attr); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci return err; 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic void ubifs_invalidatepage(struct page *page, unsigned int offset, 12918c2ecf20Sopenharmony_ci unsigned int length) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 12948c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci ubifs_assert(c, PagePrivate(page)); 12978c2ecf20Sopenharmony_ci if (offset || length < PAGE_SIZE) 12988c2ecf20Sopenharmony_ci /* Partial page remains dirty */ 12998c2ecf20Sopenharmony_ci return; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (PageChecked(page)) 13028c2ecf20Sopenharmony_ci release_new_page_budget(c); 13038c2ecf20Sopenharmony_ci else 13048c2ecf20Sopenharmony_ci release_existing_page_budget(c); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci atomic_long_dec(&c->dirty_pg_cnt); 13078c2ecf20Sopenharmony_ci detach_page_private(page); 13088c2ecf20Sopenharmony_ci ClearPageChecked(page); 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ciint ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 13148c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 13158c2ecf20Sopenharmony_ci int err; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci dbg_gen("syncing inode %lu", inode->i_ino); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (c->ro_mount) 13208c2ecf20Sopenharmony_ci /* 13218c2ecf20Sopenharmony_ci * For some really strange reasons VFS does not filter out 13228c2ecf20Sopenharmony_ci * 'fsync()' for R/O mounted file-systems as per 2.6.39. 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_ci return 0; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci err = file_write_and_wait_range(file, start, end); 13278c2ecf20Sopenharmony_ci if (err) 13288c2ecf20Sopenharmony_ci return err; 13298c2ecf20Sopenharmony_ci inode_lock(inode); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* Synchronize the inode unless this is a 'datasync()' call. */ 13328c2ecf20Sopenharmony_ci if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) { 13338c2ecf20Sopenharmony_ci err = inode->i_sb->s_op->write_inode(inode, NULL); 13348c2ecf20Sopenharmony_ci if (err) 13358c2ecf20Sopenharmony_ci goto out; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci * Nodes related to this inode may still sit in a write-buffer. Flush 13408c2ecf20Sopenharmony_ci * them. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci err = ubifs_sync_wbufs_by_inode(c, inode); 13438c2ecf20Sopenharmony_ciout: 13448c2ecf20Sopenharmony_ci inode_unlock(inode); 13458c2ecf20Sopenharmony_ci return err; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci/** 13498c2ecf20Sopenharmony_ci * mctime_update_needed - check if mtime or ctime update is needed. 13508c2ecf20Sopenharmony_ci * @inode: the inode to do the check for 13518c2ecf20Sopenharmony_ci * @now: current time 13528c2ecf20Sopenharmony_ci * 13538c2ecf20Sopenharmony_ci * This helper function checks if the inode mtime/ctime should be updated or 13548c2ecf20Sopenharmony_ci * not. If current values of the time-stamps are within the UBIFS inode time 13558c2ecf20Sopenharmony_ci * granularity, they are not updated. This is an optimization. 13568c2ecf20Sopenharmony_ci */ 13578c2ecf20Sopenharmony_cistatic inline int mctime_update_needed(const struct inode *inode, 13588c2ecf20Sopenharmony_ci const struct timespec64 *now) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci if (!timespec64_equal(&inode->i_mtime, now) || 13618c2ecf20Sopenharmony_ci !timespec64_equal(&inode->i_ctime, now)) 13628c2ecf20Sopenharmony_ci return 1; 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci/** 13678c2ecf20Sopenharmony_ci * ubifs_update_time - update time of inode. 13688c2ecf20Sopenharmony_ci * @inode: inode to update 13698c2ecf20Sopenharmony_ci * 13708c2ecf20Sopenharmony_ci * This function updates time of the inode. 13718c2ecf20Sopenharmony_ci */ 13728c2ecf20Sopenharmony_ciint ubifs_update_time(struct inode *inode, struct timespec64 *time, 13738c2ecf20Sopenharmony_ci int flags) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 13768c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 13778c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .dirtied_ino = 1, 13788c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 13798c2ecf20Sopenharmony_ci int err, release; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) 13828c2ecf20Sopenharmony_ci return generic_update_time(inode, time, flags); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 13858c2ecf20Sopenharmony_ci if (err) 13868c2ecf20Sopenharmony_ci return err; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 13898c2ecf20Sopenharmony_ci if (flags & S_ATIME) 13908c2ecf20Sopenharmony_ci inode->i_atime = *time; 13918c2ecf20Sopenharmony_ci if (flags & S_CTIME) 13928c2ecf20Sopenharmony_ci inode->i_ctime = *time; 13938c2ecf20Sopenharmony_ci if (flags & S_MTIME) 13948c2ecf20Sopenharmony_ci inode->i_mtime = *time; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci release = ui->dirty; 13978c2ecf20Sopenharmony_ci __mark_inode_dirty(inode, I_DIRTY_SYNC); 13988c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 13998c2ecf20Sopenharmony_ci if (release) 14008c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci/** 14058c2ecf20Sopenharmony_ci * update_mctime - update mtime and ctime of an inode. 14068c2ecf20Sopenharmony_ci * @inode: inode to update 14078c2ecf20Sopenharmony_ci * 14088c2ecf20Sopenharmony_ci * This function updates mtime and ctime of the inode if it is not equivalent to 14098c2ecf20Sopenharmony_ci * current time. Returns zero in case of success and a negative error code in 14108c2ecf20Sopenharmony_ci * case of failure. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_cistatic int update_mctime(struct inode *inode) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct timespec64 now = current_time(inode); 14158c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 14168c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (mctime_update_needed(inode, &now)) { 14198c2ecf20Sopenharmony_ci int err, release; 14208c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .dirtied_ino = 1, 14218c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 14248c2ecf20Sopenharmony_ci if (err) 14258c2ecf20Sopenharmony_ci return err; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 14288c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 14298c2ecf20Sopenharmony_ci release = ui->dirty; 14308c2ecf20Sopenharmony_ci mark_inode_dirty_sync(inode); 14318c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 14328c2ecf20Sopenharmony_ci if (release) 14338c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return 0; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic ssize_t ubifs_write_iter(struct kiocb *iocb, struct iov_iter *from) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci int err = update_mctime(file_inode(iocb->ki_filp)); 14428c2ecf20Sopenharmony_ci if (err) 14438c2ecf20Sopenharmony_ci return err; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return generic_file_write_iter(iocb, from); 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic int ubifs_set_page_dirty(struct page *page) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci int ret; 14518c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 14528c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci ret = __set_page_dirty_nobuffers(page); 14558c2ecf20Sopenharmony_ci /* 14568c2ecf20Sopenharmony_ci * An attempt to dirty a page without budgeting for it - should not 14578c2ecf20Sopenharmony_ci * happen. 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci ubifs_assert(c, ret == 0); 14608c2ecf20Sopenharmony_ci return ret; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci#ifdef CONFIG_MIGRATION 14648c2ecf20Sopenharmony_cistatic int ubifs_migrate_page(struct address_space *mapping, 14658c2ecf20Sopenharmony_ci struct page *newpage, struct page *page, enum migrate_mode mode) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci int rc; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci rc = migrate_page_move_mapping(mapping, newpage, page, 0); 14708c2ecf20Sopenharmony_ci if (rc != MIGRATEPAGE_SUCCESS) 14718c2ecf20Sopenharmony_ci return rc; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (PagePrivate(page)) { 14748c2ecf20Sopenharmony_ci detach_page_private(page); 14758c2ecf20Sopenharmony_ci attach_page_private(newpage, (void *)1); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (mode != MIGRATE_SYNC_NO_COPY) 14798c2ecf20Sopenharmony_ci migrate_page_copy(newpage, page); 14808c2ecf20Sopenharmony_ci else 14818c2ecf20Sopenharmony_ci migrate_page_states(newpage, page); 14828c2ecf20Sopenharmony_ci return MIGRATEPAGE_SUCCESS; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci#endif 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cistatic int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 14898c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* 14928c2ecf20Sopenharmony_ci * An attempt to release a dirty page without budgeting for it - should 14938c2ecf20Sopenharmony_ci * not happen. 14948c2ecf20Sopenharmony_ci */ 14958c2ecf20Sopenharmony_ci if (PageWriteback(page)) 14968c2ecf20Sopenharmony_ci return 0; 14978c2ecf20Sopenharmony_ci ubifs_assert(c, PagePrivate(page)); 14988c2ecf20Sopenharmony_ci ubifs_assert(c, 0); 14998c2ecf20Sopenharmony_ci detach_page_private(page); 15008c2ecf20Sopenharmony_ci ClearPageChecked(page); 15018c2ecf20Sopenharmony_ci return 1; 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci/* 15058c2ecf20Sopenharmony_ci * mmap()d file has taken write protection fault and is being made writable. 15068c2ecf20Sopenharmony_ci * UBIFS must ensure page is budgeted for. 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_cistatic vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct page *page = vmf->page; 15118c2ecf20Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 15128c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 15138c2ecf20Sopenharmony_ci struct timespec64 now = current_time(inode); 15148c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_page = 1 }; 15158c2ecf20Sopenharmony_ci int err, update_time; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index, 15188c2ecf20Sopenharmony_ci i_size_read(inode)); 15198c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (unlikely(c->ro_error)) 15228c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* -EROFS */ 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * We have not locked @page so far so we may budget for changing the 15268c2ecf20Sopenharmony_ci * page. Note, we cannot do this after we locked the page, because 15278c2ecf20Sopenharmony_ci * budgeting may cause write-back which would cause deadlock. 15288c2ecf20Sopenharmony_ci * 15298c2ecf20Sopenharmony_ci * At the moment we do not know whether the page is dirty or not, so we 15308c2ecf20Sopenharmony_ci * assume that it is not and budget for a new page. We could look at 15318c2ecf20Sopenharmony_ci * the @PG_private flag and figure this out, but we may race with write 15328c2ecf20Sopenharmony_ci * back and the page state may change by the time we lock it, so this 15338c2ecf20Sopenharmony_ci * would need additional care. We do not bother with this at the 15348c2ecf20Sopenharmony_ci * moment, although it might be good idea to do. Instead, we allocate 15358c2ecf20Sopenharmony_ci * budget for a new page and amend it later on if the page was in fact 15368c2ecf20Sopenharmony_ci * dirty. 15378c2ecf20Sopenharmony_ci * 15388c2ecf20Sopenharmony_ci * The budgeting-related logic of this function is similar to what we 15398c2ecf20Sopenharmony_ci * do in 'ubifs_write_begin()' and 'ubifs_write_end()'. Glance there 15408c2ecf20Sopenharmony_ci * for more comments. 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_ci update_time = mctime_update_needed(inode, &now); 15438c2ecf20Sopenharmony_ci if (update_time) 15448c2ecf20Sopenharmony_ci /* 15458c2ecf20Sopenharmony_ci * We have to change inode time stamp which requires extra 15468c2ecf20Sopenharmony_ci * budgeting. 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_ci req.dirtied_ino = 1; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 15518c2ecf20Sopenharmony_ci if (unlikely(err)) { 15528c2ecf20Sopenharmony_ci if (err == -ENOSPC) 15538c2ecf20Sopenharmony_ci ubifs_warn(c, "out of space for mmapped file (inode number %lu)", 15548c2ecf20Sopenharmony_ci inode->i_ino); 15558c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci lock_page(page); 15598c2ecf20Sopenharmony_ci if (unlikely(page->mapping != inode->i_mapping || 15608c2ecf20Sopenharmony_ci page_offset(page) > i_size_read(inode))) { 15618c2ecf20Sopenharmony_ci /* Page got truncated out from underneath us */ 15628c2ecf20Sopenharmony_ci goto sigbus; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (PagePrivate(page)) 15668c2ecf20Sopenharmony_ci release_new_page_budget(c); 15678c2ecf20Sopenharmony_ci else { 15688c2ecf20Sopenharmony_ci if (!PageChecked(page)) 15698c2ecf20Sopenharmony_ci ubifs_convert_page_budget(c); 15708c2ecf20Sopenharmony_ci attach_page_private(page, (void *)1); 15718c2ecf20Sopenharmony_ci atomic_long_inc(&c->dirty_pg_cnt); 15728c2ecf20Sopenharmony_ci __set_page_dirty_nobuffers(page); 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (update_time) { 15768c2ecf20Sopenharmony_ci int release; 15778c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 15808c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 15818c2ecf20Sopenharmony_ci release = ui->dirty; 15828c2ecf20Sopenharmony_ci mark_inode_dirty_sync(inode); 15838c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 15848c2ecf20Sopenharmony_ci if (release) 15858c2ecf20Sopenharmony_ci ubifs_release_dirty_inode_budget(c, ui); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci wait_for_stable_page(page); 15898c2ecf20Sopenharmony_ci return VM_FAULT_LOCKED; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cisigbus: 15928c2ecf20Sopenharmony_ci unlock_page(page); 15938c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 15948c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic const struct vm_operations_struct ubifs_file_vm_ops = { 15988c2ecf20Sopenharmony_ci .fault = filemap_fault, 15998c2ecf20Sopenharmony_ci .map_pages = filemap_map_pages, 16008c2ecf20Sopenharmony_ci .page_mkwrite = ubifs_vm_page_mkwrite, 16018c2ecf20Sopenharmony_ci}; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_cistatic int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci int err; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci err = generic_file_mmap(file, vma); 16088c2ecf20Sopenharmony_ci if (err) 16098c2ecf20Sopenharmony_ci return err; 16108c2ecf20Sopenharmony_ci vma->vm_ops = &ubifs_file_vm_ops; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) 16138c2ecf20Sopenharmony_ci file_accessed(file); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci return 0; 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic const char *ubifs_get_link(struct dentry *dentry, 16198c2ecf20Sopenharmony_ci struct inode *inode, 16208c2ecf20Sopenharmony_ci struct delayed_call *done) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (!IS_ENCRYPTED(inode)) 16258c2ecf20Sopenharmony_ci return ui->data; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (!dentry) 16288c2ecf20Sopenharmony_ci return ERR_PTR(-ECHILD); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return fscrypt_get_symlink(inode, ui->data, ui->data_len, done); 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int ubifs_symlink_getattr(const struct path *path, struct kstat *stat, 16348c2ecf20Sopenharmony_ci u32 request_mask, unsigned int query_flags) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci ubifs_getattr(path, stat, request_mask, query_flags); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(d_inode(path->dentry))) 16398c2ecf20Sopenharmony_ci return fscrypt_symlink_getattr(path, stat); 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ciconst struct address_space_operations ubifs_file_address_operations = { 16448c2ecf20Sopenharmony_ci .readpage = ubifs_readpage, 16458c2ecf20Sopenharmony_ci .writepage = ubifs_writepage, 16468c2ecf20Sopenharmony_ci .write_begin = ubifs_write_begin, 16478c2ecf20Sopenharmony_ci .write_end = ubifs_write_end, 16488c2ecf20Sopenharmony_ci .invalidatepage = ubifs_invalidatepage, 16498c2ecf20Sopenharmony_ci .set_page_dirty = ubifs_set_page_dirty, 16508c2ecf20Sopenharmony_ci#ifdef CONFIG_MIGRATION 16518c2ecf20Sopenharmony_ci .migratepage = ubifs_migrate_page, 16528c2ecf20Sopenharmony_ci#endif 16538c2ecf20Sopenharmony_ci .releasepage = ubifs_releasepage, 16548c2ecf20Sopenharmony_ci}; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ciconst struct inode_operations ubifs_file_inode_operations = { 16578c2ecf20Sopenharmony_ci .setattr = ubifs_setattr, 16588c2ecf20Sopenharmony_ci .getattr = ubifs_getattr, 16598c2ecf20Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_XATTR 16608c2ecf20Sopenharmony_ci .listxattr = ubifs_listxattr, 16618c2ecf20Sopenharmony_ci#endif 16628c2ecf20Sopenharmony_ci .update_time = ubifs_update_time, 16638c2ecf20Sopenharmony_ci}; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ciconst struct inode_operations ubifs_symlink_inode_operations = { 16668c2ecf20Sopenharmony_ci .get_link = ubifs_get_link, 16678c2ecf20Sopenharmony_ci .setattr = ubifs_setattr, 16688c2ecf20Sopenharmony_ci .getattr = ubifs_symlink_getattr, 16698c2ecf20Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_XATTR 16708c2ecf20Sopenharmony_ci .listxattr = ubifs_listxattr, 16718c2ecf20Sopenharmony_ci#endif 16728c2ecf20Sopenharmony_ci .update_time = ubifs_update_time, 16738c2ecf20Sopenharmony_ci}; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ciconst struct file_operations ubifs_file_operations = { 16768c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 16778c2ecf20Sopenharmony_ci .read_iter = generic_file_read_iter, 16788c2ecf20Sopenharmony_ci .write_iter = ubifs_write_iter, 16798c2ecf20Sopenharmony_ci .mmap = ubifs_file_mmap, 16808c2ecf20Sopenharmony_ci .fsync = ubifs_fsync, 16818c2ecf20Sopenharmony_ci .unlocked_ioctl = ubifs_ioctl, 16828c2ecf20Sopenharmony_ci .splice_read = generic_file_splice_read, 16838c2ecf20Sopenharmony_ci .splice_write = iter_file_splice_write, 16848c2ecf20Sopenharmony_ci .open = fscrypt_file_open, 16858c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 16868c2ecf20Sopenharmony_ci .compat_ioctl = ubifs_compat_ioctl, 16878c2ecf20Sopenharmony_ci#endif 16888c2ecf20Sopenharmony_ci}; 1689