⛏️ index : haiku.git

author Jim906 <jim_l@fastmail.com> 2025-06-25 9:56:45.0 -04:00:00
committer waddlesplash <waddlesplash@gmail.com> 2025-06-26 14:44:39.0 +00:00:00
commit
3738985e2ca0dfa9dcf9b9df5fa391b7047fa24e [patch]
tree
041cd7e7a372b018680a5b08d61bf28828d6b75c
parent
2b9fdf7847804ba0ed6b7826a308402b86882ca6
download
3738985e2ca0dfa9dcf9b9df5fa391b7047fa24e.tar.gz

fat: Fix error handling in buffer IO functions

* Have bread() output a NULL *bpp when returning an error (consistent
  with FreeBSD).

* Enable brelse() to handle a NULL argument (consistent with FreeBSD).

* Ensure that when getblkx() returns an error, no clean-up remains to
  be done by bread() or getblk().

* Let allocate_data() set buf::b_owned, and set it only if successful
  in allocating, so the flag won't be misleading to put_buf() after a
  failure.

* Revise vput() to avoid situations when, after an error, it might
  call put_vnode() before the node is published to the VFS.

Change-Id: I42cc1684fe5b68333284b149e72a794c93ac71ff
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9393
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>

Diff

 src/add-ons/kernel/file_systems/fat/bsd/kern/vfs_bio.c | 31 +++++++++++++++++++++++--------
 src/add-ons/kernel/file_systems/fat/bsd/sys/vnode.h    |  6 +++++-
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/fat/bsd/kern/vfs_bio.c b/src/add-ons/kernel/file_systems/fat/bsd/kern/vfs_bio.c
index 45bbd0a..5495ea3 100644
--- a/src/add-ons/kernel/file_systems/fat/bsd/kern/vfs_bio.c
+++ b/src/add-ons/kernel/file_systems/fat/bsd/kern/vfs_bio.c
@@ -95,6 +95,8 @@

	if (error == 0)
		*bpp = buf;
	else
		*bpp = NULL;

	return error;
}
@@ -198,12 +200,15 @@
}


/*! Each bread call must be balanced with either a b(d/a)write (to write changes) or a brelse.

/*! Each successful bread call must be balanced with either a b(d/a)write (to write changes) or a
	brelse.
*/
void
brelse(struct buf* bp)
{
	if (bp == NULL)
		return;

	if (bp->b_vreg != NULL) {
		put_buf(bp);
		return;
@@ -262,6 +267,7 @@
	@param splflag Ignored in the port.
	@param slptimeo Ignored in the port.
	@param flags Ignored in the port.
	@param bpp If no error is returned, *bpp contains the address of the requested buf.
*/
int
getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, int slptimeo,
@@ -363,10 +369,11 @@
		off_t fileOffset;
		size_t bytesRead;

		newBuf->b_owned = true;
		status = allocate_data(newBuf, size);
		if (status != B_OK)
		if (status != B_OK) {
			put_buf(newBuf);
			return B_TO_POSIX_ERROR(status);
		}

		// Don't use the file cache while resizing; wait until node lock is released to avoid
		// deadlocks.
@@ -374,7 +381,7 @@
			(*bpp) = newBuf;
				// we need to return a buffer with b_data allocated even in this case,
				// because detrunc may zero out the unused space at the end of the last cluster
			return B_TO_POSIX_ERROR(status);
			return 0;
		}

		fileOffset = de_cn2off(fatVolume, blkno);
@@ -402,10 +409,11 @@
		newBuf->b_bufsize = CACHED_BLOCK_SIZE;
	} else {
		// need to get more than one cached block and copy them to make a continuous buffer
		newBuf->b_owned = true;
		status = allocate_data(newBuf, size);
		if (status != 0)
		if (status != 0) {
			put_buf(newBuf);
			return B_TO_POSIX_ERROR(status);
		}

#ifdef _KERNEL_MODE
		// for high block counts, try to get all blocks in one disk read
@@ -415,7 +423,7 @@
		}
#endif // _KERNEL_MODE

		for (i = 0; i < cBlockCount && status == B_OK; i++) {
		for (i = 0; i < cBlockCount; i++) {
			if (readOnly == true)
				newBuf->b_bcpointers[i] = (void*)block_cache_get(blockCache, dblkno + i);
			else
@@ -438,7 +446,7 @@

	*bpp = newBuf;

	return B_TO_POSIX_ERROR(status);
	return 0;
}


@@ -503,7 +511,8 @@


/*! Added for the Haiku port. Ensure that buf->b_data points to 'size' bytes of zero'd memory.

	@post If no error is returned, buf->b_owned is set to true. If an error is returned,
	no memory is allocated for buf->b_data.
*/
static status_t
allocate_data(struct buf* buf, int size)
@@ -527,6 +536,8 @@
			buf->b_bufsize = size;
		}
	}

	buf->b_owned = true;

	return B_OK;
}
diff --git a/src/add-ons/kernel/file_systems/fat/bsd/sys/vnode.h b/src/add-ons/kernel/file_systems/fat/bsd/sys/vnode.h
index 734f191..a8f1342 100644
--- a/src/add-ons/kernel/file_systems/fat/bsd/sys/vnode.h
+++ b/src/add-ons/kernel/file_systems/fat/bsd/sys/vnode.h
@@ -246,7 +246,11 @@
static inline void
vput(struct vnode* vp)
{
	put_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);
	// The driver might call vput to balance a getnewvnode() call. The getnewvnode stand-in
	// written for the Haiku port, which leaves the node in VSTATE_UNINITIALIZED, doesn't get a
	// ref to the node though.
	if (vp->v_state != VSTATE_UNINITIALIZED)
		put_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);

	rw_lock_write_unlock(&vp->v_vnlock->haikuRW);
}