// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation. * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter
*/
/* * This file implements VFS file and inode operations for regular files, device * nodes and symlinks as well as address space operations. * * UBIFS uses 2 page flags: @PG_private and @PG_checked. @PG_private is set if * the page is dirty and is used for optimization purposes - dirty pages are * not budgeted so the flag shows that 'ubifs_write_end()' should not release * the budget for this page. The @PG_checked flag is set if full budgeting is * required for the page e.g., when it corresponds to a file hole or it is * beyond the file size. The budgeting is done in 'ubifs_write_begin()', because * it is OK to fail in this function, and the budget is released in * 'ubifs_write_end()'. So the @PG_private and @PG_checked flags carry * information about how the page was budgeted, to make it possible to release * the budget properly. * * A thing to keep in mind: inode @i_mutex is locked in most VFS operations we * implement. However, this is not true for 'ubifs_writepage()', which may be * called with @i_mutex unlocked. For example, when flusher thread is doing * background write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. * At "normal" work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. * in the "sys_write -> alloc_pages -> direct reclaim path". So, in * 'ubifs_writepage()' we are only guaranteed that the page is locked. * * Similarly, @i_mutex is not always locked in 'ubifs_read_folio()', e.g., the * read-ahead path does not lock it ("sys_read -> generic_file_aio_read -> * ondemand_readahead -> read_folio"). In case of readahead, @I_SYNC flag is not * set as well. However, UBIFS disables readahead.
*/
data_key_init(c, &key, inode->i_ino, block);
err = ubifs_tnc_lookup(c, &key, dn); if (err) { if (err == -ENOENT) /* Not found, so it must be a hole */
folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE); return err;
}
ubifs_assert(c, le64_to_cpu(dn->ch.sqnum) >
ubifs_inode(inode)->creat_sqnum);
len = le32_to_cpu(dn->size); if (len <= 0 || len > UBIFS_BLOCK_SIZE) goto dump;
if (IS_ENCRYPTED(inode)) {
err = ubifs_decrypt(inode, dn, &dlen, block); if (err) goto dump;
}
out_len = UBIFS_BLOCK_SIZE;
err = ubifs_decompress_folio(c, &dn->data, dlen, folio, offset,
&out_len, le16_to_cpu(dn->compr_type)); if (err || len != out_len) goto dump;
/* * Data length can be less than a full block, even for blocks that are * not the last in the file (e.g., as a result of making a hole and * appending data). Ensure that the remainder is zeroed out.
*/ if (len < UBIFS_BLOCK_SIZE)
folio_zero_range(folio, offset + len, UBIFS_BLOCK_SIZE - len);
if (err) { struct ubifs_info *c = inode->i_sb->s_fs_info; if (err == -ENOENT) { /* Not found, so it must be a hole */
folio_set_checked(folio);
dbg_gen("hole");
err = 0;
} else {
ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
folio->index, inode->i_ino, err);
}
}
out:
kfree(dn); if (!err)
folio_mark_uptodate(folio); return err;
}
/** * release_new_page_budget - release budget of a new page. * @c: UBIFS file-system description object * * This is a helper function which releases budget corresponding to the budget * of one new page of data.
*/ staticvoid release_new_page_budget(struct ubifs_info *c)
{ struct ubifs_budget_req req = { .recalculate = 1, .new_page = 1 };
ubifs_release_budget(c, &req);
}
/** * release_existing_page_budget - release budget of an existing page. * @c: UBIFS file-system description object * * This is a helper function which releases budget corresponding to the budget * of changing one page of data which already exists on the flash media.
*/ staticvoid release_existing_page_budget(struct ubifs_info *c)
{ struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
/* * At the slow path we have to budget before locking the folio, because * budgeting may force write-back, which would wait on locked folios and * deadlock if we had the folio locked. At this point we do not know * anything about the folio, so assume that this is a new folio which is * written to a hole. This corresponds to largest budget. Later the * budget will be amended if this is not true.
*/ if (appending) /* We are appending data, budget for inode change */
req.dirtied_ino = 1;
err = ubifs_budget_space(c, &req); if (unlikely(err)) return err;
if (!folio_test_uptodate(folio)) { if (pos == folio_pos(folio) && len >= folio_size(folio))
folio_set_checked(folio); else {
err = do_readpage(folio); if (err) {
folio_unlock(folio);
folio_put(folio);
ubifs_release_budget(c, &req); return err;
}
}
}
if (folio->private) /* * The folio is dirty, which means it was budgeted twice: * o first time the budget was allocated by the task which * made the folio dirty and set the private field; * o and then we budgeted for it for the second time at the * very beginning of this function. * * So what we have to do is to release the folio budget we * allocated.
*/
release_new_page_budget(c); elseif (!folio_test_checked(folio)) /* * We are changing a folio which already exists on the media. * This means that changing the folio does not make the amount * of indexing information larger, and this part of the budget * which we have already acquired may be released.
*/
ubifs_convert_page_budget(c);
if (appending) { struct ubifs_inode *ui = ubifs_inode(inode);
/* * 'ubifs_write_end()' is optimized from the fast-path part of * 'ubifs_write_begin()' and expects the @ui_mutex to be locked * if data is appended.
*/
mutex_lock(&ui->ui_mutex); if (ui->dirty) /* * The inode is dirty already, so we may free the * budget we allocated.
*/
ubifs_release_dirty_inode_budget(c, ui);
}
*foliop = folio; return 0;
}
/** * allocate_budget - allocate budget for 'ubifs_write_begin()'. * @c: UBIFS file-system description object * @folio: folio to allocate budget for * @ui: UBIFS inode object the page belongs to * @appending: non-zero if the page is appended * * This is a helper function for 'ubifs_write_begin()' which allocates budget * for the operation. The budget is allocated differently depending on whether * this is appending, whether the page is dirty or not, and so on. This * function leaves the @ui->ui_mutex locked in case of appending. * * Returns: %0 in case of success and %-ENOSPC in case of failure.
*/ staticint allocate_budget(struct ubifs_info *c, struct folio *folio, struct ubifs_inode *ui, int appending)
{ struct ubifs_budget_req req = { .fast = 1 };
if (folio->private) { if (!appending) /* * The folio is dirty and we are not appending, which * means no budget is needed at all.
*/ return 0;
mutex_lock(&ui->ui_mutex); if (ui->dirty) /* * The page is dirty and we are appending, so the inode * has to be marked as dirty. However, it is already * dirty, so we do not need any budget. We may return, * but @ui->ui_mutex hast to be left locked because we * should prevent write-back from flushing the inode * and freeing the budget. The lock will be released in * 'ubifs_write_end()'.
*/ return 0;
/* * The page is dirty, we are appending, the inode is clean, so * we need to budget the inode change.
*/
req.dirtied_ino = 1;
} else { if (folio_test_checked(folio)) /* * The page corresponds to a hole and does not * exist on the media. So changing it makes * the amount of indexing information * larger, and we have to budget for a new * page.
*/
req.new_page = 1; else /* * Not a hole, the change will not add any new * indexing information, budget for page * change.
*/
req.dirtied_page = 1;
if (appending) {
mutex_lock(&ui->ui_mutex); if (!ui->dirty) /* * The inode is clean but we will have to mark * it as dirty because we are appending. This * needs a budget.
*/
req.dirtied_ino = 1;
}
}
return ubifs_budget_space(c, &req);
}
/* * This function is called when a page of data is going to be written. Since * the page of data will not necessarily go to the flash straight away, UBIFS * has to reserve space on the media for it, which is done by means of * budgeting. * * This is the hot-path of the file-system and we are trying to optimize it as * much as possible. For this reasons it is split on 2 parts - slow and fast. * * There many budgeting cases: * o a new page is appended - we have to budget for a new page and for * changing the inode; however, if the inode is already dirty, there is * no need to budget for it; * o an existing clean page is changed - we have budget for it; if the page * does not exist on the media (a hole), we have to budget for a new * page; otherwise, we may budget for changing an existing page; the * difference between these cases is that changing an existing page does * not introduce anything new to the FS indexing information, so it does * not grow, and smaller budget is acquired in this case; * o an existing dirty page is changed - no need to budget at all, because * the page budget has been acquired by earlier, when the page has been * marked dirty. * * UBIFS budgeting sub-system may force write-back if it thinks there is no * space to reserve. This imposes some locking restrictions and makes it * impossible to take into account the above cases, and makes it impossible to * optimize budgeting. * * The solution for this is that the fast path of 'ubifs_write_begin()' assumes * there is a plenty of flash space and the budget will be acquired quickly, * without forcing write-back. The slow path does not make this assumption.
*/ staticint ubifs_write_begin(conststruct kiocb *iocb, struct address_space *mapping,
loff_t pos, unsigned len, struct folio **foliop, void **fsdata)
{ struct inode *inode = mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_inode *ui = ubifs_inode(inode);
pgoff_t index = pos >> PAGE_SHIFT; int err, appending = !!(pos + len > inode->i_size); int skipped_read = 0; struct folio *folio;
/* Try out the fast-path part first */
folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
mapping_gfp_mask(mapping)); if (IS_ERR(folio)) return PTR_ERR(folio);
if (!folio_test_uptodate(folio)) { /* The page is not loaded from the flash */ if (pos == folio_pos(folio) && len >= folio_size(folio)) { /* * We change whole page so no need to load it. But we * do not know whether this page exists on the media or * not, so we assume the latter because it requires * larger budget. The assumption is that it is better * to budget a bit more than to read the page from the * media. Thus, we are setting the @PG_checked flag * here.
*/
folio_set_checked(folio);
skipped_read = 1;
} else {
err = do_readpage(folio); if (err) {
folio_unlock(folio);
folio_put(folio); return err;
}
}
}
err = allocate_budget(c, folio, ui, appending); if (unlikely(err)) {
ubifs_assert(c, err == -ENOSPC); /* * If we skipped reading the page because we were going to * write all of it, then it is not up to date.
*/ if (skipped_read)
folio_clear_checked(folio); /* * Budgeting failed which means it would have to force * write-back but didn't, because we set the @fast flag in the * request. Write-back cannot be done now, while we have the * page locked, because it would deadlock. Unlock and free * everything and fall-back to slow-path.
*/ if (appending) {
ubifs_assert(c, mutex_is_locked(&ui->ui_mutex));
mutex_unlock(&ui->ui_mutex);
}
folio_unlock(folio);
folio_put(folio);
/* * Whee, we acquired budgeting quickly - without involving * garbage-collection, committing or forcing write-back. We return * with @ui->ui_mutex locked if we are appending pages, and unlocked * otherwise. This is an optimization (slightly hacky though).
*/
*foliop = folio; return 0;
}
/** * cancel_budget - cancel budget. * @c: UBIFS file-system description object * @folio: folio to cancel budget for * @ui: UBIFS inode object the page belongs to * @appending: non-zero if the page is appended * * This is a helper function for a page write operation. It unlocks the * @ui->ui_mutex in case of appending.
*/ staticvoid cancel_budget(struct ubifs_info *c, struct folio *folio, struct ubifs_inode *ui, int appending)
{ if (appending) { if (!ui->dirty)
ubifs_release_dirty_inode_budget(c, ui);
mutex_unlock(&ui->ui_mutex);
} if (!folio->private) { if (folio_test_checked(folio))
release_new_page_budget(c); else
release_existing_page_budget(c);
}
}
if (unlikely(copied < len && !folio_test_uptodate(folio))) { /* * VFS copied less data to the folio than it intended and * declared in its '->write_begin()' call via the @len * argument. If the folio was not up-to-date, * the 'ubifs_write_begin()' function did * not load it from the media (for optimization reasons). This * means that part of the folio contains garbage. So read the * folio now.
*/
dbg_gen("copied %d instead of %d, read page and repeat",
copied, len);
cancel_budget(c, folio, ui, appending);
folio_clear_checked(folio);
/* * Return 0 to force VFS to repeat the whole operation, or the * error code if 'do_readpage()' fails.
*/
copied = do_readpage(folio); goto out;
}
if (len == folio_size(folio))
folio_mark_uptodate(folio);
if (!folio->private) {
folio_attach_private(folio, (void *)1);
atomic_long_inc(&c->dirty_pg_cnt);
filemap_dirty_folio(mapping, folio);
}
if (appending) {
i_size_write(inode, end_pos);
ui->ui_size = end_pos; /* * We do not set @I_DIRTY_PAGES (which means that * the inode has dirty pages), this was done in * filemap_dirty_folio().
*/
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
ubifs_assert(c, mutex_is_locked(&ui->ui_mutex));
mutex_unlock(&ui->ui_mutex);
}
/** * ubifs_do_bulk_read - do bulk-read. * @c: UBIFS file-system description object * @bu: bulk-read information * @folio1: first folio to read * * Returns: %1 if the bulk-read is done, otherwise %0 is returned.
*/ staticint ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, struct folio *folio1)
{
pgoff_t offset = folio1->index, end_index; struct address_space *mapping = folio1->mapping; struct inode *inode = mapping->host; struct ubifs_inode *ui = ubifs_inode(inode); int err, page_idx, page_cnt, ret = 0, n = 0; int allocate = bu->buf ? 0 : 1;
loff_t isize;
gfp_t ra_gfp_mask = readahead_gfp_mask(mapping) & ~__GFP_FS;
err = ubifs_tnc_get_bu_keys(c, bu); if (err) goto out_warn;
if (bu->eof) { /* Turn off bulk-read at the end of the file */
ui->read_in_a_row = 1;
ui->bulk_read = 0;
}
page_cnt = bu->blk_cnt >> UBIFS_BLOCKS_PER_PAGE_SHIFT; if (!page_cnt) { /* * This happens when there are multiple blocks per page and the * blocks for the first page we are looking for, are not * together. If all the pages were like this, bulk-read would * reduce performance, so we turn it off for a while.
*/ goto out_bu_off;
}
if (bu->cnt) { if (allocate) { /* * Allocate bulk-read buffer depending on how many data * nodes we are going to read.
*/
bu->buf_len = bu->zbranch[bu->cnt - 1].offs +
bu->zbranch[bu->cnt - 1].len -
bu->zbranch[0].offs;
ubifs_assert(c, bu->buf_len > 0);
ubifs_assert(c, bu->buf_len <= c->leb_size);
bu->buf = kmalloc(bu->buf_len, GFP_NOFS | __GFP_NOWARN); if (!bu->buf) goto out_bu_off;
}
err = ubifs_tnc_bulk_read(c, bu); if (err) goto out_warn;
}
err = populate_page(c, folio1, bu, &n); if (err) goto out_warn;
/** * ubifs_bulk_read - determine whether to bulk-read and, if so, do it. * @folio: folio from which to start bulk-read. * * Some flash media are capable of reading sequentially at faster rates. UBIFS * bulk-read facility is designed to take advantage of that, by reading in one * go consecutive data nodes that are also located consecutively in the same * LEB. * * Returns: %1 if a bulk-read is done and %0 otherwise.
*/ staticint ubifs_bulk_read(struct folio *folio)
{ struct inode *inode = folio->mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_inode *ui = ubifs_inode(inode);
pgoff_t index = folio->index, last_page_read = ui->last_page_read; struct bu_info *bu; int err = 0, allocated = 0;
ui->last_page_read = index; if (!c->bulk_read) return 0;
/* * Bulk-read is protected by @ui->ui_mutex, but it is an optimization, * so don't bother if we cannot lock the mutex.
*/ if (!mutex_trylock(&ui->ui_mutex)) return 0;
if (index != last_page_read + 1) { /* Turn off bulk-read if we stop reading sequentially */
ui->read_in_a_row = 1; if (ui->bulk_read)
ui->bulk_read = 0; goto out_unlock;
}
if (!ui->bulk_read) {
ui->read_in_a_row += 1; if (ui->read_in_a_row < 3) goto out_unlock; /* Three reads in a row, so switch on bulk-read */
ui->bulk_read = 1;
}
/* * If possible, try to use pre-allocated bulk-read information, which * is protected by @c->bu_mutex.
*/ if (mutex_trylock(&c->bu_mutex))
bu = &c->bu; else {
bu = kmalloc(sizeof(struct bu_info), GFP_NOFS | __GFP_NOWARN); if (!bu) goto out_unlock;
/* * When writing-back dirty inodes, VFS first writes-back pages belonging to the * inode, then the inode itself. For UBIFS this may cause a problem. Consider a * situation when a we have an inode with size 0, then a megabyte of data is * appended to the inode, then write-back starts and flushes some amount of the * dirty pages, the journal becomes full, commit happens and finishes, and then * an unclean reboot happens. When the file system is mounted next time, the * inode size would still be 0, but there would be many pages which are beyond * the inode size, they would be indexed and consume flash space. Because the * journal has been committed, the replay would not be able to detect this * situation and correct the inode size. This means UBIFS would have to scan * whole index and correct all inode sizes, which is long an unacceptable. * * To prevent situations like this, UBIFS writes pages back only if they are * within the last synchronized inode size, i.e. the size which has been * written to the flash media last time. Otherwise, UBIFS forces inode * write-back, thus making sure the on-flash inode contains current inode size, * and then keeps writing pages back. * * Some locking issues explanation. 'ubifs_writepage()' first is called with * the page locked, and it locks @ui_mutex. However, write-back does take inode * @i_mutex, which means other VFS operations may be run on this inode at the * same time. And the problematic one is truncation to smaller size, from where * we have to call 'truncate_setsize()', which first changes @inode->i_size, * then drops the truncated pages. And while dropping the pages, it takes the * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. * This means that @inode->i_size is changed while @ui_mutex is unlocked. * * XXX(truncate): with the new truncate sequence this is not true anymore, * and the calls to truncate_setsize can be move around freely. They should * be moved to the very end of the truncate sequence. * * But in 'ubifs_writepage()' we have to guarantee that we do not write beyond * inode size. How do we do this if @inode->i_size may became smaller while we * are in the middle of 'ubifs_writepage()'? The UBIFS solution is the * @ui->ui_isize "shadow" field which UBIFS uses instead of @inode->i_size * internally and updates it under @ui_mutex. * * Q: why we do not worry that if we race with truncation, we may end up with a * situation when the inode is truncated while we are in the middle of * 'do_writepage()', so we do write beyond inode size? * A: If we are in the middle of 'do_writepage()', truncation would be locked * on the page lock and it would not write the truncated inode node to the * journal before we have finished.
*/ staticint ubifs_writepage(struct folio *folio, struct writeback_control *wbc)
{ struct inode *inode = folio->mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_inode *ui = ubifs_inode(inode);
loff_t i_size = i_size_read(inode), synced_i_size; int err, len = folio_size(folio);
/* Is the folio fully inside i_size? */ if (folio_pos(folio) + len <= i_size) { if (folio_pos(folio) + len > synced_i_size) {
err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) goto out_redirty; /* * The inode has been written, but the write-buffer has * not been synchronized, so in case of an unclean * reboot we may end up with some pages beyond inode * size, but they would be in the journal (because * commit flushes write buffers) and recovery would deal * with this.
*/
} return do_writepage(folio, len);
}
/* * The folio straddles @i_size. It must be zeroed out on each and every * writepage invocation because it may be mmapped. "A file is mapped * in multiples of the page size. For a file that is not a multiple of * the page size, the remaining memory is zeroed when mapped, and * writes to that region are not written out to the file."
*/
len = i_size - folio_pos(folio);
folio_zero_segment(folio, len, folio_size(folio));
if (i_size > synced_i_size) {
err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) goto out_redirty;
}
return do_writepage(folio, len);
out_redirty: /* * folio_redirty_for_writepage() won't call ubifs_dirty_inode() because * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so * there is no need to do space budget for dirty inode.
*/
folio_redirty_for_writepage(wbc, folio);
out_unlock:
folio_unlock(folio); return err;
}
/* * If this is truncation to a smaller size, and we do not truncate on a * block boundary, budget for changing one data block, because the last * block will be re-written.
*/ if (new_size & (UBIFS_BLOCK_SIZE - 1))
req.dirtied_page = 1;
req.dirtied_ino = 1; /* A funny way to budget for truncation node */
req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ;
err = ubifs_budget_space(c, &req); if (err) { /* * Treat truncations to zero as deletion and always allow them, * just like we do for '->unlink()'.
*/ if (new_size || err != -ENOSPC) return err;
budgeted = 0;
}
truncate_setsize(inode, new_size);
if (offset) {
pgoff_t index = new_size >> PAGE_SHIFT; struct folio *folio;
folio = filemap_lock_folio(inode->i_mapping, index); if (!IS_ERR(folio)) { if (folio_test_dirty(folio)) { /* * 'ubifs_jnl_truncate()' will try to truncate * the last data node, but it contains * out-of-date data because the page is dirty. * Write the page now, so that * 'ubifs_jnl_truncate()' will see an already * truncated (and up to date) data node.
*/
ubifs_assert(c, folio->private != NULL);
folio_clear_dirty_for_io(folio); if (UBIFS_BLOCKS_PER_PAGE_SHIFT)
offset = offset_in_folio(folio,
new_size);
err = do_writepage(folio, offset);
folio_put(folio); if (err) goto out_budg; /* * We could now tell 'ubifs_jnl_truncate()' not * to read the last block.
*/
} else { /* * We could 'kmap()' the page and pass the data * to 'ubifs_jnl_truncate()' to save it from * having to read it.
*/
folio_unlock(folio);
folio_put(folio);
}
}
}
mutex_lock(&ui->ui_mutex);
ui->ui_size = inode->i_size; /* Truncation changes inode [mc]time */
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); /* Other attributes may be changed at the same time as well */
do_attr_changes(inode, attr);
err = ubifs_jnl_truncate(c, inode, old_size, new_size);
mutex_unlock(&ui->ui_mutex);
release = ui->dirty; if (attr->ia_valid & ATTR_SIZE) /* * Inode length changed, so we have to make sure * @I_DIRTY_DATASYNC is set.
*/
__mark_inode_dirty(inode, I_DIRTY_DATASYNC); else
mark_inode_dirty_sync(inode);
mutex_unlock(&ui->ui_mutex);
if (release)
ubifs_release_budget(c, &req); if (IS_SYNC(inode))
err = inode->i_sb->s_op->write_inode(inode, NULL); return err;
}
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{ struct inode *inode = file->f_mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; int err;
dbg_gen("syncing inode %lu", inode->i_ino);
if (c->ro_mount) /* * For some really strange reasons VFS does not filter out * 'fsync()' for R/O mounted file-systems as per 2.6.39.
*/ return 0;
err = file_write_and_wait_range(file, start, end); if (err) return err;
inode_lock(inode);
/* Synchronize the inode unless this is a 'datasync()' call. */ if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) {
err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) goto out;
}
/* * Nodes related to this inode may still sit in a write-buffer. Flush * them.
*/
err = ubifs_sync_wbufs_by_inode(c, inode);
out:
inode_unlock(inode); return err;
}
/** * mctime_update_needed - check if mtime or ctime update is needed. * @inode: the inode to do the check for * @now: current time * * This helper function checks if the inode mtime/ctime should be updated or * not. If current values of the time-stamps are within the UBIFS inode time * granularity, they are not updated. This is an optimization. * * Returns: %1 if time update is needed, %0 if not
*/ staticinlineint mctime_update_needed(conststruct inode *inode, conststruct timespec64 *now)
{ struct timespec64 ctime = inode_get_ctime(inode); struct timespec64 mtime = inode_get_mtime(inode);
/** * ubifs_update_time - update time of inode. * @inode: inode to update * @flags: time updating control flag determines updating * which time fields of @inode * * This function updates time of the inode. * * Returns: %0 for success or a negative error code otherwise.
*/ int ubifs_update_time(struct inode *inode, int flags)
{ struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(ui->data_len, 8) }; int err, release;
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) {
generic_update_time(inode, flags); return 0;
}
err = ubifs_budget_space(c, &req); if (err) return err;
/** * update_mctime - update mtime and ctime of an inode. * @inode: inode to update * * This function updates mtime and ctime of the inode if it is not equivalent to * current time. * * Returns: %0 in case of success and a negative error code in * case of failure.
*/ staticint update_mctime(struct inode *inode)
{ struct timespec64 now = current_time(inode); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info;
if (mctime_update_needed(inode, &now)) { int err, release; struct ubifs_budget_req req = { .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(ui->data_len, 8) };
err = ubifs_budget_space(c, &req); if (err) return err;
ret = filemap_dirty_folio(mapping, folio); /* * An attempt to dirty a page without budgeting for it - should not * happen.
*/
ubifs_assert(c, ret == false); return ret;
}
/* * Page is private but not dirty, weird? There is one condition * making it happened. ubifs_writepage skipped the page because * page index beyonds isize (for example. truncated by other * process named A), then the page is invalidated by fadvise64 * syscall before being truncated by process A.
*/
ubifs_assert(c, folio_test_private(folio)); if (folio_test_checked(folio))
release_new_page_budget(c); else
release_existing_page_budget(c);
if (unlikely(c->ro_error)) return VM_FAULT_SIGBUS; /* -EROFS */
/* * We have not locked @folio so far so we may budget for changing the * folio. Note, we cannot do this after we locked the folio, because * budgeting may cause write-back which would cause deadlock. * * At the moment we do not know whether the folio is dirty or not, so we * assume that it is not and budget for a new folio. We could look at * the @PG_private flag and figure this out, but we may race with write * back and the folio state may change by the time we lock it, so this * would need additional care. We do not bother with this at the * moment, although it might be good idea to do. Instead, we allocate * budget for a new folio and amend it later on if the folio was in fact * dirty. * * The budgeting-related logic of this function is similar to what we * do in 'ubifs_write_begin()' and 'ubifs_write_end()'. Glance there * for more comments.
*/
update_time = mctime_update_needed(inode, &now); if (update_time) /* * We have to change inode time stamp which requires extra * budgeting.
*/
req.dirtied_ino = 1;
err = ubifs_budget_space(c, &req); if (unlikely(err)) { if (err == -ENOSPC)
ubifs_warn(c, "out of space for mmapped file (inode number %lu)",
inode->i_ino); return VM_FAULT_SIGBUS;
}
folio_lock(folio); if (unlikely(folio->mapping != inode->i_mapping ||
folio_pos(folio) >= i_size_read(inode))) { /* Folio got truncated out from underneath us */ goto sigbus;
}
if (folio->private)
release_new_page_budget(c); else { if (!folio_test_checked(folio))
ubifs_convert_page_budget(c);
folio_attach_private(folio, (void *)1);
atomic_long_inc(&c->dirty_pg_cnt);
filemap_dirty_folio(folio->mapping, folio);
}
if (update_time) { int release; struct ubifs_inode *ui = ubifs_inode(inode);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.