Module Name: src
Committed By: christos
Date: Tue Apr 12 14:40:16 UTC 2016
Modified Files:
src/sys/ufs/ufs: ufs_lookup.c
Log Message:
- Collect the slot-related variables in their own structure and extract
some of the slot finding and updating code into their own function.
- Add a new label "next" in the main search loop to avoid nesting and
code duplication.
- Cache some reclen and ino variables for better readability and efficiency.
To generate a diff of this commit:
cvs rdiff -u -r1.137 -r1.138 src/sys/ufs/ufs/ufs_lookup.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/ufs/ufs/ufs_lookup.c
diff -u src/sys/ufs/ufs/ufs_lookup.c:1.137 src/sys/ufs/ufs/ufs_lookup.c:1.138
--- src/sys/ufs/ufs/ufs_lookup.c:1.137 Mon Apr 11 20:36:29 2016
+++ src/sys/ufs/ufs/ufs_lookup.c Tue Apr 12 10:40:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_lookup.c,v 1.137 2016/04/12 00:36:29 christos Exp $ */
+/* $NetBSD: ufs_lookup.c,v 1.138 2016/04/12 14:40:16 christos Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.137 2016/04/12 00:36:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.138 2016/04/12 14:40:16 christos Exp $");
#ifdef _KERNEL_OPT
#include "opt_ffs.h"
@@ -93,6 +93,111 @@ ufs_dirswap(struct direct *dirp)
dirp->d_type = tmp;
}
+struct slotinfo {
+ enum {
+ NONE, /* need to search a slot for our new entry */
+ COMPACT, /* a compaction can make a slot in the current
+ DIRBLKSIZ block */
+ FOUND, /* found a slot (or no need to search) */
+ } status;
+ doff_t offset; /* offset of area with free space.
+ a special value -1 for invalid */
+ int size; /* size of area at slotoffset */
+ int freespace; /* accumulated amount of space free in
+ the current DIRBLKSIZ block */
+ int needed; /* size of the entry we're seeking */
+};
+
+static void
+slot_init(struct slotinfo *slot)
+{
+ slot->status = FOUND;
+ slot->offset = -1;
+ slot->freespace = slot->size = slot->needed = 0;
+}
+
+#ifdef UFS_DIRHASH
+static doff_t
+slot_findfree(struct slotinfo *slot, struct inode *dp)
+{
+ if (slot->status == FOUND)
+ return dp->i_size;
+
+ slot->offset = ufsdirhash_findfree(dp, slot->needed, &slot->size);
+ if (slot->offset < 0)
+ return dp->i_size;
+
+ slot->status = COMPACT;
+ doff_t enduseful = ufsdirhash_enduseful(dp);
+ if (enduseful < 0)
+ return dp->i_size;
+ return enduseful;
+}
+#endif
+
+static void
+slot_white(struct slotinfo *slot, uint16_t reclen,
+ struct ufs_lookup_results *results)
+{
+ slot->status = FOUND;
+ slot->offset = results->ulr_offset;
+ slot->size = reclen;
+ results->ulr_reclen = slot->size;
+}
+
+static void
+slot_update(struct slotinfo *slot, int size, uint16_t reclen, doff_t offset)
+{
+ if (size >= slot->needed) {
+ slot->status = FOUND;
+ slot->offset = offset;
+ slot->size = reclen;
+ } else if (slot->status == NONE) {
+ slot->freespace += size;
+ if (slot->offset == -1)
+ slot->offset = offset;
+ if (slot->freespace >= slot->needed) {
+ slot->status = COMPACT;
+ slot->size = offset + reclen - slot->offset;
+ }
+ }
+}
+
+/*
+ * Return an indication of where the new directory entry should be put.
+ * If we didn't find a slot, then set results->ulr_count to 0 indicating
+ * that the new slot belongs at the end of the directory. If we found a slot,
+ * then the new entry can be put in the range from results->ulr_offset to
+ * results->ulr_offset + results->ulr_count.
+ */
+static int
+slot_estimate(const struct slotinfo *slot, int dirblksiz, int nameiop,
+ doff_t prevoff, doff_t enduseful, const struct inode *ip,
+ struct ufs_lookup_results *results)
+{
+ if (slot->status == NONE) {
+ results->ulr_offset = roundup(ip->i_size, dirblksiz);
+ results->ulr_count = 0;
+ enduseful = results->ulr_offset;
+ } else if (nameiop == DELETE) {
+ results->ulr_offset = slot->offset;
+ if ((results->ulr_offset & (dirblksiz - 1)) == 0)
+ results->ulr_count = 0;
+ else
+ results->ulr_count = results->ulr_offset - prevoff;
+ } else {
+ results->ulr_offset = slot->offset;
+ results->ulr_count = slot->size;
+ if (enduseful < slot->offset + slot->size)
+ enduseful = slot->offset + slot->size;
+ }
+ results->ulr_endoff = roundup(enduseful, dirblksiz);
+#if 0 /* commented out by dbj. none of the on disk fields changed */
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+#endif
+ return EJUSTRETURN;
+}
+
/*
* Convert a component of a pathname into a pointer to a locked inode.
* This is a very central and rather complicated routine.
@@ -139,18 +244,7 @@ ufs_lookup(void *v)
struct buf *bp; /* a buffer of directory entries */
struct direct *ep; /* the current directory entry */
int entryoffsetinblock; /* offset of ep in bp's buffer */
- enum {
- NONE, /* need to search a slot for our new entry */
- COMPACT, /* a compaction can make a slot in the current
- DIRBLKSIZ block */
- FOUND, /* found a slot (or no need to search) */
- } slotstatus;
- doff_t slotoffset; /* offset of area with free space.
- a special value -1 for invalid */
- int slotsize; /* size of area at slotoffset */
- int slotfreespace; /* accumulated amount of space free in
- the current DIRBLKSIZ block */
- int slotneeded; /* size of the entry we're seeking */
+ struct slotinfo slot;
int numdirpasses; /* strategy for directory search */
doff_t endsearch; /* offset to end directory search */
doff_t prevoff; /* previous value of ulr_offset */
@@ -171,11 +265,11 @@ ufs_lookup(void *v)
struct ufs_lookup_results *results;
int iswhiteout; /* temp result from cache_lookup() */
const int fsfmt = FSFMT(vdp);
+ uint16_t reclen;
flags = cnp->cn_flags;
bp = NULL;
- slotoffset = -1;
*vpp = NULL;
endsearch = 0; /* silence compiler warning */
@@ -233,11 +327,11 @@ ufs_lookup(void *v)
* we watch for a place to put the new file in
* case it doesn't already exist.
*/
- slotstatus = FOUND;
- slotfreespace = slotsize = slotneeded = 0;
+ slot_init(&slot);
+
if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) {
- slotstatus = NONE;
- slotneeded = UFS_DIRECTSIZ(cnp->cn_namelen);
+ slot.status = NONE;
+ slot.needed = UFS_DIRECTSIZ(cnp->cn_namelen);
}
/*
@@ -262,22 +356,13 @@ ufs_lookup(void *v)
*/
if (ufsdirhash_build(dp) == 0) {
/* Look for a free slot if needed. */
- enduseful = dp->i_size;
- if (slotstatus != FOUND) {
- slotoffset = ufsdirhash_findfree(dp, slotneeded,
- &slotsize);
- if (slotoffset >= 0) {
- slotstatus = COMPACT;
- enduseful = ufsdirhash_enduseful(dp);
- if (enduseful < 0)
- enduseful = dp->i_size;
- }
- }
+ enduseful = slot_findfree(&slot, dp->i_size);
/* Look up the component. */
numdirpasses = 1;
entryoffsetinblock = 0; /* silence compiler warning */
switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
- &results->ulr_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) {
+ &results->ulr_offset, &bp,
+ nameiop == DELETE ? &prevoff : NULL)) {
case 0:
ep = (void *)((char *)bp->b_data +
(results->ulr_offset & bmask));
@@ -330,10 +415,10 @@ searchloop:
* If still looking for a slot, and at a DIRBLKSIZ
* boundary, have to start looking for free space again.
*/
- if (slotstatus == NONE &&
+ if (slot.status == NONE &&
(entryoffsetinblock & (dirblksiz - 1)) == 0) {
- slotoffset = -1;
- slotfreespace = 0;
+ slot.offset = -1;
+ slot.freespace = 0;
}
/*
* Get pointer to next entry.
@@ -345,15 +430,13 @@ searchloop:
KASSERT(bp != NULL);
ep = (void *)((char *)bp->b_data + entryoffsetinblock);
const char *msg;
- if ((ep->d_reclen == 0 && (msg = "null entry")) || (dirchk &&
+ reclen = ufs_rw16(ep->d_reclen, needswap);
+ if ((reclen == 0 && (msg = "null entry")) || (dirchk &&
(msg = ufs_dirbadentry(vdp, ep, entryoffsetinblock)))) {
- int i;
-
ufs_dirbad(dp, results->ulr_offset, msg);
- i = dirblksiz - (entryoffsetinblock & (dirblksiz - 1));
- results->ulr_offset += i;
- entryoffsetinblock += i;
- continue;
+ reclen = dirblksiz -
+ (entryoffsetinblock & (dirblksiz - 1));
+ goto next;
}
/*
@@ -362,84 +445,60 @@ searchloop:
* in the current block so that we can determine if
* compaction is viable.
*/
- if (slotstatus != FOUND) {
- int size = ufs_rw16(ep->d_reclen, needswap);
-
+ if (slot.status != FOUND) {
+ int size = reclen;
if (ep->d_ino != 0)
size -= UFS_DIRSIZ(fsfmt, ep, needswap);
- if (size > 0) {
- if (size >= slotneeded) {
- slotstatus = FOUND;
- slotoffset = results->ulr_offset;
- slotsize = ufs_rw16(ep->d_reclen,
- needswap);
- } else if (slotstatus == NONE) {
- slotfreespace += size;
- if (slotoffset == -1)
- slotoffset = results->ulr_offset;
- if (slotfreespace >= slotneeded) {
- slotstatus = COMPACT;
- slotsize = results->ulr_offset +
- ufs_rw16(ep->d_reclen,
- needswap) -
- slotoffset;
- }
- }
- }
+ if (size > 0)
+ slot_update(&slot, size, reclen,
+ results->ulr_offset);
}
+ if (ep->d_ino == 0)
+ goto next;
+
/*
* Check for a name match.
*/
- if (ep->d_ino) {
- const int namlen = NAMLEN(fsfmt, needswap, ep);
- if (namlen == cnp->cn_namelen &&
- !memcmp(cnp->cn_nameptr, ep->d_name,
- (unsigned)namlen)) {
+ const uint16_t namlen = NAMLEN(fsfmt, needswap, ep);
+ if (namlen != cnp->cn_namelen ||
+ memcmp(cnp->cn_nameptr, ep->d_name,
+ (unsigned)namlen))
+ goto next;
+
#ifdef UFS_DIRHASH
foundentry:
#endif
- /*
- * Save directory entry's inode number and
- * reclen, and release directory buffer.
- */
- if (!fsfmt && ep->d_type == DT_WHT) {
- slotstatus = FOUND;
- slotoffset = results->ulr_offset;
- slotsize = ufs_rw16(ep->d_reclen,
- needswap);
- results->ulr_reclen = slotsize;
- /*
- * This is used to set
- * results->ulr_endoff,
- * which may be used by ufs_direnter()
- * as a length to truncate the
- * directory to. Therefore, it must
- * point past the end of the last
- * non-empty directory entry. We don't
- * know where that is in this case, so
- * we effectively disable shrinking by
- * using the existing size of the
- * directory.
- *
- * Note that we wouldn't expect to
- * shrink the directory while rewriting
- * an existing entry anyway.
- */
- enduseful = endsearch;
- cnp->cn_flags |= ISWHITEOUT;
- numdirpasses--;
- goto notfound;
- }
- foundino = ufs_rw32(ep->d_ino, needswap);
- results->ulr_reclen =
- ufs_rw16(ep->d_reclen, needswap);
- goto found;
- }
+ /*
+ * Save directory entry's inode number and
+ * reclen, and release directory buffer.
+ */
+ if (!fsfmt && ep->d_type == DT_WHT) {
+ slot_white(&slot, reclen, results);
+ /*
+ * This is used to set results->ulr_endoff, which may
+ * be used by ufs_direnter() as a length to truncate
+ * the directory to. Therefore, it must point past the
+ * end of the last non-empty directory entry. We don't
+ * know where that is in this case, so we effectively
+ * disable shrinking by using the existing size of the
+ * directory.
+ *
+ * Note that we wouldn't expect to shrink the
+ * directory while rewriting an existing entry anyway.
+ */
+ enduseful = endsearch;
+ cnp->cn_flags |= ISWHITEOUT;
+ numdirpasses--;
+ goto notfound;
}
+ foundino = ufs_rw32(ep->d_ino, needswap);
+ results->ulr_reclen = reclen;
+ goto found;
+next:
prevoff = results->ulr_offset;
- results->ulr_offset += ufs_rw16(ep->d_reclen, needswap);
- entryoffsetinblock += ufs_rw16(ep->d_reclen, needswap);
+ results->ulr_offset += reclen;
+ entryoffsetinblock += reclen;
if (ep->d_ino)
enduseful = results->ulr_offset;
}
@@ -473,36 +532,8 @@ notfound:
error = VOP_ACCESS(vdp, VWRITE, cred);
if (error)
goto out;
- /*
- * Return an indication of where the new directory
- * entry should be put. If we didn't find a slot,
- * then set results->ulr_count to 0 indicating
- * that the new slot belongs at the end of the
- * directory. If we found a slot, then the new entry
- * can be put in the range from results->ulr_offset to
- * results->ulr_offset + results->ulr_count.
- */
- if (slotstatus == NONE) {
- results->ulr_offset = roundup(dp->i_size, dirblksiz);
- results->ulr_count = 0;
- enduseful = results->ulr_offset;
- } else if (nameiop == DELETE) {
- results->ulr_offset = slotoffset;
- if ((results->ulr_offset & (dirblksiz - 1)) == 0)
- results->ulr_count = 0;
- else
- results->ulr_count =
- results->ulr_offset - prevoff;
- } else {
- results->ulr_offset = slotoffset;
- results->ulr_count = slotsize;
- if (enduseful < slotoffset + slotsize)
- enduseful = slotoffset + slotsize;
- }
- results->ulr_endoff = roundup(enduseful, dirblksiz);
-#if 0 /* commented out by dbj. none of the on disk fields changed */
- dp->i_flag |= IN_CHANGE | IN_UPDATE;
-#endif
+ error = slot_estimate(&slot, dirblksiz, nameiop,
+ prevoff, enduseful, dp, results);
/*
* We return with the directory locked, so that
* the parameters we set up above will still be
@@ -514,7 +545,6 @@ notfound:
* NB - if the directory is unlocked, then this
* information cannot be used.
*/
- error = EJUSTRETURN;
goto out;
}
/*
@@ -551,7 +581,7 @@ found:
* in the cache as to where the entry was found.
*/
if ((flags & ISLASTCN) && nameiop == LOOKUP)
- results->ulr_diroff = results->ulr_offset &~ (dirblksiz - 1);
+ results->ulr_diroff = results->ulr_offset & ~(dirblksiz - 1);
/*
* If deleting, and at end of pathname, return
@@ -660,11 +690,11 @@ void
ufs_dirbad(struct inode *ip, doff_t offset, const char *how)
{
struct mount *mp = ITOV(ip)->v_mount;
- void (*p)(const char *, ...) =
+ void (*p)(const char *, ...) __printflike(1, 2) =
(mp->mnt_flag & MNT_RDONLY) == 0 ? panic : printf;
- (*p)("%s: bad dir ino %llu at offset %d: %s\n",
- mp->mnt_stat.f_mntonname, (unsigned long long)ip->i_number,
+ (*p)("%s: bad dir ino %ju at offset %d: %s\n",
+ mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number,
offset, how);
}
@@ -684,8 +714,8 @@ ufs_dirbadentry(struct vnode *dp, struct
const int dirblksiz = ump->um_dirblksiz;
const int maxsize = dirblksiz - (entryoffsetinblock & (dirblksiz - 1));
const int fsfmt = FSFMT(dp);
- const int namlen = NAMLEN(fsfmt, needswap, ep);
- const int reclen = ufs_rw16(ep->d_reclen, needswap);
+ const uint16_t namlen = NAMLEN(fsfmt, needswap, ep);
+ const uint16_t reclen = ufs_rw16(ep->d_reclen, needswap);
const int dirsiz = (int)UFS_DIRSIZ(fsfmt, ep, needswap);
const char *str;
@@ -794,6 +824,7 @@ ufs_direnter(struct vnode *dvp, const st
const int needswap = UFS_MPNEEDSWAP(ump);
int dirblksiz = ump->um_dirblksiz;
const int fsfmt = FSFMT(dvp);
+ uint16_t reclen;
UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
@@ -883,10 +914,9 @@ ufs_direnter(struct vnode *dvp, const st
*/
ep = (void *)dirbuf;
dsize = (ep->d_ino != 0) ? UFS_DIRSIZ(fsfmt, ep, needswap) : 0;
- spacefree = ufs_rw16(ep->d_reclen, needswap) - dsize;
- for (loc = ufs_rw16(ep->d_reclen, needswap); loc < ulr->ulr_count; ) {
- uint16_t reclen;
-
+ reclen = ufs_rw16(ep->d_reclen, needswap);
+ spacefree = reclen - dsize;
+ for (loc = reclen; loc < ulr->ulr_count; ) {
nep = (void *)(dirbuf + loc);
/* Trim the existing slot (NB: dsize may be zero). */
@@ -1021,6 +1051,7 @@ ufs_dirremove(struct vnode *dvp, const s
struct buf *bp;
int error;
const int needswap = UFS_MPNEEDSWAP(dp->i_ump);
+ uint16_t reclen;
UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
@@ -1041,6 +1072,7 @@ ufs_dirremove(struct vnode *dvp, const s
(off_t)(ulr->ulr_offset - ulr->ulr_count), &ep, &bp, true)) != 0)
return (error);
+ reclen = ufs_rw16(ep->d_reclen, needswap);
#ifdef UFS_DIRHASH
/*
* Remove the dirhash entry. This is complicated by the fact
@@ -1048,8 +1080,7 @@ ufs_dirremove(struct vnode *dvp, const s
*/
if (dp->i_dirhash != NULL)
ufsdirhash_remove(dp, (ulr->ulr_count == 0) ? ep :
- (void *)((char *)ep +
- ufs_rw16(ep->d_reclen, needswap)), ulr->ulr_offset);
+ (void *)((char *)ep + reclen), ulr->ulr_offset);
#endif
if (ulr->ulr_count == 0) {
@@ -1061,9 +1092,7 @@ ufs_dirremove(struct vnode *dvp, const s
/*
* Collapse new free space into previous entry.
*/
- ep->d_reclen =
- ufs_rw16(ufs_rw16(ep->d_reclen, needswap) + ulr->ulr_reclen,
- needswap);
+ ep->d_reclen = ufs_rw16(reclen + ulr->ulr_reclen, needswap);
}
#ifdef UFS_DIRHASH
@@ -1187,10 +1216,11 @@ ufs_dirempty(struct inode *ip, ino_t par
if (dp->d_reclen == 0)
return (0);
/* skip empty entries */
- if (dp->d_ino == 0 || ufs_rw32(dp->d_ino, needswap) == UFS_WINO)
+ ino_t ino = ufs_rw32(dp->d_ino, needswap);
+ if (ino == 0 || ino == UFS_WINO)
continue;
/* accept only "." and ".." */
- const int namlen = NAMLEN(fsfmt, needswap, dp);
+ const uint16_t namlen = NAMLEN(fsfmt, needswap, dp);
if (namlen > 2)
return (0);
if (dp->d_name[0] != '.')
@@ -1200,11 +1230,9 @@ ufs_dirempty(struct inode *ip, ino_t par
* 1 implies ".", 2 implies ".." if second
* char is also "."
*/
- if (namlen == 1 &&
- ufs_rw32(dp->d_ino, needswap) == ip->i_number)
+ if (namlen == 1 && ino == ip->i_number)
continue;
- if (dp->d_name[1] == '.' &&
- ufs_rw32(dp->d_ino, needswap) == parentino)
+ if (dp->d_name[1] == '.' && ino == parentino)
continue;
return (0);
}