/* get the directory entry of given file or directory */ if (exfat_get_dentry_set_by_ei(&es, sb, ei)) return -EIO;
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);
/* File size should be zero if there is no cluster allocated */
on_disk_size = i_size_read(inode);
if (ei->start_clu == EXFAT_EOF_CLUSTER)
on_disk_size = 0;
ep2->dentry.stream.size = cpu_to_le64(on_disk_size); /* * mmap write does not use exfat_write_end(), valid_size may be * extended to the sector-aligned length in exfat_get_block(). * So we need to fixup valid_size to the writren length.
*/ if (on_disk_size < ei->valid_size)
ep2->dentry.stream.valid_size = ep2->dentry.stream.size; else
ep2->dentry.stream.valid_size = cpu_to_le64(ei->valid_size);
/* append to the FAT chain */ if (last_clu == EXFAT_EOF_CLUSTER) { if (new_clu.flags == ALLOC_FAT_CHAIN)
ei->flags = ALLOC_FAT_CHAIN;
ei->start_clu = new_clu.dir;
} else { if (new_clu.flags != ei->flags) { /* no-fat-chain bit is disabled, * so fat-chain should be synced with * alloc-bitmap
*/
exfat_chain_cont_cluster(sb, ei->start_clu,
num_clusters);
ei->flags = ALLOC_FAT_CHAIN;
} if (new_clu.flags == ALLOC_FAT_CHAIN) if (exfat_ent_set(sb, last_clu, new_clu.dir)) return -EIO;
}
/* * Move *clu pointer along FAT chains (hole care) because the * caller of this function expect *clu to be the last cluster. * This only works when num_to_be_allocated >= 2, * *clu = (the first cluster of the allocated chain) => * (the last cluster of ...)
*/ if (ei->flags == ALLOC_NO_FAT_CHAIN) {
*clu += num_to_be_allocated - 1;
} else { while (num_to_be_allocated > 1) { if (exfat_get_next_cluster(sb, clu)) return -EIO;
num_to_be_allocated--;
}
}
}
/* hint information */
ei->hint_bmap.off = local_clu_offset;
ei->hint_bmap.clu = *clu;
map_bh(bh_result, sb, phys); if (buffer_delay(bh_result))
clear_buffer_delay(bh_result);
/* * In most cases, we just need to set bh_result to mapped, unmapped * or new status as follows: * 1. i_size == valid_size * 2. write case (create == 1) * 3. direct_read (!bh_result->b_folio) * -> the unwritten part will be zeroed in exfat_direct_IO() * * Otherwise, in the case of buffered read, it is necessary to take * care the last nested block if valid_size is not equal to i_size.
*/ if (i_size == ei->valid_size || create || !bh_result->b_folio)
valid_blks = EXFAT_B_TO_BLK_ROUND_UP(ei->valid_size, sb); else
valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);
/* The range has been fully written, map it */ if (iblock + max_blocks < valid_blks) goto done;
/* The range has been partially written, map the written part */ if (iblock < valid_blks) {
max_blocks = valid_blks - iblock; goto done;
}
/* The area has not been written, map and mark as new for create case */ if (create) {
set_buffer_new(bh_result);
ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
mark_inode_dirty(inode); goto done;
}
/* * The area has just one block partially written. * In that case, we should read and fill the unwritten part of * a block with zero.
*/ if (bh_result->b_folio && iblock == valid_blks &&
(ei->valid_size & (sb->s_blocksize - 1))) {
loff_t size, pos; void *addr;
max_blocks = 1;
/* * No buffer_head is allocated. * (1) bmap: It's enough to set blocknr without I/O. * (2) read: The unwritten part should be filled with zero. * If a folio does not have any buffers, * let's returns -EAGAIN to fallback to * block_read_full_folio() for per-bh IO.
*/ if (!folio_buffers(bh_result->b_folio)) {
err = -EAGAIN; goto done;
}
/* Check if bh->b_data points to proper addr in folio */ if (bh_result->b_data != addr) {
exfat_fs_error_ratelimit(sb, "b_data(%p) != folio_addr(%p)",
bh_result->b_data, addr);
err = -EINVAL; goto done;
}
/* Read a block */
err = bh_read(bh_result, 0); if (err < 0) goto done;
/* Zero unwritten part of a block */
memset(bh_result->b_data + size, 0, bh_result->b_size - size);
err = 0; goto done;
}
/* * The area has not been written, clear mapped for read/bmap cases. * If so, it will be filled with zero without reading from disk.
*/
clear_buffer_mapped(bh_result);
done:
bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); if (err < 0)
clear_buffer_mapped(bh_result);
unlock_ret:
mutex_unlock(&sbi->s_lock); return err;
}
/* * Need to use the DIO_LOCKING for avoiding the race * condition of exfat_get_block() and ->truncate().
*/
ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); if (ret < 0) { if (rw == WRITE && ret != -EIOCBQUEUED)
exfat_write_failed(mapping, size);
return ret;
} else
size = pos + ret;
if (rw == WRITE) { /* * If the block had been partially written before this write, * ->valid_size will not be updated in exfat_get_block(), * update it here.
*/ if (ei->valid_size < size) {
ei->valid_size = size;
mark_inode_dirty(inode);
}
} elseif (pos < ei->valid_size && ei->valid_size < size) { /* zero the unwritten part in the partially written block */
iov_iter_revert(iter, size - ei->valid_size);
iov_iter_zero(size - ei->valid_size, iter);
}
/* * exfat_block_truncate_page() zeroes out a mapping from file offset `from' * up to the end of the block which corresponds to `from'. * This is required during truncate to physically zeroout the tail end * of that block so it doesn't yield old data if the file is later grown. * Also, avoid causing failure from fsx for cases of "data past EOF"
*/ int exfat_block_truncate_page(struct inode *inode, loff_t from)
{ return block_truncate_page(inode->i_mapping, from, exfat_get_block);
}
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.