pull freebsd's ufs_lookup.c rev.1.53 and 1.54. PR/31873.
> ---------------------------- > revision 1.54 > date: 2001/08/26 01:25:12; author: iedowse; state: Exp; lines: +30 -12 > When compacting directories, ufs_direnter() always trusted DIRSIZ() > to supply the number of bytes to be bcopy()'d to move an entry. If > d_ino == 0 however, DIRSIZ() is not guaranteed to return a sensible > length, so ufs_direnter could end up corrupting a directory during > compaction. In practice I believe this can only happen after fsck_ffs > has fixed a previously-corrupted directory. > > We now deal with any mid-block unused entries specially to avoid > using DIRSIZ() or bcopy() on such entries. We also ensure that the > variables 'dsize' and 'spacefree' contain meaningful values at all > times. Add a few comments to describe better this intricate piece > of code. > > The special handling of mid-block unused entries makes the dirhash- > specific bugfix in the previous revision (1.53) now uncecessary, > so this change removes it. > > Reviewed by: mckusick > ---------------------------- > revision 1.53 > date: 2001/08/22 01:35:17; author: iedowse; state: Exp; lines: +2 -2 > When compressing directory blocks, the dirhash code didn't check > that the directory entry was in use before attempting to find it > in the hash structures to change its offset. Normally, unused > entries do not need to be moved, but fsck can leave behind some > unused entries that do. A dirhash sanity panic resulted when the > entry to be moved was not found. Add a check that stops entries > with d_ino == 0 from being passed to ufsdirhash_move().
This commit is contained in:
parent
cabee93abb
commit
3a6eed1f58
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ufs_lookup.c,v 1.71 2006/01/13 00:50:58 yamt Exp $ */
|
||||
/* $NetBSD: ufs_lookup.c,v 1.72 2006/01/14 09:09:02 yamt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.71 2006/01/13 00:50:58 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.72 2006/01/14 09:09:02 yamt Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_ffs.h"
|
||||
@ -908,21 +908,36 @@ ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,
|
||||
* dp->i_offset + dp->i_count would yield the space.
|
||||
*/
|
||||
ep = (struct direct *)dirbuf;
|
||||
dsize = DIRSIZ(FSFMT(dvp), ep, needswap);
|
||||
dsize = ufs_rw32(ep->d_ino, needswap) ?
|
||||
DIRSIZ(FSFMT(dvp), ep, needswap) : 0;
|
||||
spacefree = ufs_rw16(ep->d_reclen, needswap) - dsize;
|
||||
for (loc = ufs_rw16(ep->d_reclen, needswap); loc < dp->i_count; ) {
|
||||
uint16_t reclen;
|
||||
|
||||
nep = (struct direct *)(dirbuf + loc);
|
||||
if (ep->d_ino) {
|
||||
/* trim the existing slot */
|
||||
ep->d_reclen = ufs_rw16(dsize, needswap);
|
||||
ep = (struct direct *)((char *)ep + dsize);
|
||||
} else {
|
||||
/* overwrite; nothing there; header is ours */
|
||||
spacefree += dsize;
|
||||
|
||||
/* Trim the existing slot (NB: dsize may be zero). */
|
||||
ep->d_reclen = ufs_rw16(dsize, needswap);
|
||||
ep = (struct direct *)((char *)ep + dsize);
|
||||
|
||||
reclen = ufs_rw16(nep->d_reclen, needswap);
|
||||
loc += reclen;
|
||||
if (nep->d_ino == 0) {
|
||||
/*
|
||||
* A mid-block unused entry. Such entries are
|
||||
* never created by the kernel, but fsck_ffs
|
||||
* can create them (and it doesn't fix them).
|
||||
*
|
||||
* Add up the free space, and initialise the
|
||||
* relocated entry since we don't memcpy it.
|
||||
*/
|
||||
spacefree += reclen;
|
||||
ep->d_ino = 0;
|
||||
dsize = 0;
|
||||
continue;
|
||||
}
|
||||
dsize = DIRSIZ(FSFMT(dvp), nep, needswap);
|
||||
spacefree += ufs_rw16(nep->d_reclen, needswap) - dsize;
|
||||
loc += ufs_rw16(nep->d_reclen, needswap);
|
||||
spacefree += reclen - dsize;
|
||||
#ifdef UFS_DIRHASH
|
||||
if (dp->i_dirhash != NULL)
|
||||
ufsdirhash_move(dp, nep,
|
||||
@ -936,6 +951,11 @@ ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,
|
||||
memcpy((caddr_t)ep, (caddr_t)nep, dsize);
|
||||
}
|
||||
/*
|
||||
* Here, `ep' points to a directory entry containing `dsize' in-use
|
||||
* bytes followed by `spacefree' unused bytes. If ep->d_ino == 0,
|
||||
* then the entry is completely unused (dsize == 0). The value
|
||||
* of ep->d_reclen is always indeterminate.
|
||||
*
|
||||
* Update the pointer fields in the previous entry (if any),
|
||||
* copy in the new entry, and write out the block.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user