mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 08:12:27 -04:00
makefs/zfs: Ensure that the last block of a file has the right size
When copying a file's contents into the pool, a loop copies blocks of the maximum size (128KB), allocating space from the vdev for each block. The space allocator rounds up to the nearest block size, but for files larger than the maximum size, this can result in the last block having a smaller logical size than the rest of the blocks belonging to that dnode. This violates some ZFS invariants when appending to that file. Modify fs_populate_file() to use the same block size for the final block. Reported by: cperciva MFC after: 1 week Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
d9d69a6f6f
commit
ef20cd33d3
1 changed files with 10 additions and 9 deletions
|
|
@ -515,7 +515,7 @@ fs_populate_file(fsnode *cur, struct fs_populate_arg *arg)
|
|||
uint64_t dnid;
|
||||
ssize_t n;
|
||||
size_t bufsz;
|
||||
off_t size, target;
|
||||
off_t nbytes, reqbytes, size;
|
||||
int fd;
|
||||
|
||||
assert(cur->type == S_IFREG);
|
||||
|
|
@ -546,29 +546,30 @@ fs_populate_file(fsnode *cur, struct fs_populate_arg *arg)
|
|||
bufsz = sizeof(zfs->filebuf);
|
||||
size = cur->inode->st.st_size;
|
||||
c = dnode_cursor_init(zfs, arg->fs->os, dnode, size, 0);
|
||||
for (off_t foff = 0; foff < size; foff += target) {
|
||||
for (off_t foff = 0; foff < size; foff += nbytes) {
|
||||
off_t loc, sofar;
|
||||
|
||||
/*
|
||||
* Fill up our buffer, handling partial reads.
|
||||
*/
|
||||
sofar = 0;
|
||||
target = MIN(size - foff, (off_t)bufsz);
|
||||
nbytes = MIN(size - foff, (off_t)bufsz);
|
||||
do {
|
||||
n = read(fd, buf + sofar, target);
|
||||
n = read(fd, buf + sofar, nbytes);
|
||||
if (n < 0)
|
||||
err(1, "reading from '%s'", cur->name);
|
||||
if (n == 0)
|
||||
errx(1, "unexpected EOF reading '%s'",
|
||||
cur->name);
|
||||
sofar += n;
|
||||
} while (sofar < target);
|
||||
} while (sofar < nbytes);
|
||||
|
||||
if (target < (off_t)bufsz)
|
||||
memset(buf + target, 0, bufsz - target);
|
||||
if (nbytes < (off_t)bufsz)
|
||||
memset(buf + nbytes, 0, bufsz - nbytes);
|
||||
|
||||
loc = objset_space_alloc(zfs, arg->fs->os, &target);
|
||||
vdev_pwrite_dnode_indir(zfs, dnode, 0, 1, buf, target, loc,
|
||||
reqbytes = foff == 0 ? nbytes : MAXBLOCKSIZE;
|
||||
loc = objset_space_alloc(zfs, arg->fs->os, &reqbytes);
|
||||
vdev_pwrite_dnode_indir(zfs, dnode, 0, 1, buf, reqbytes, loc,
|
||||
dnode_cursor_next(zfs, c, foff));
|
||||
}
|
||||
eclose(fd);
|
||||
|
|
|
|||
Loading…
Reference in a new issue