summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'libexec')
-rw-r--r--libexec/lfs_cleanerd/cleaner.h3
-rw-r--r--libexec/lfs_cleanerd/coalesce.c85
-rw-r--r--libexec/lfs_cleanerd/lfs_cleanerd.c35
3 files changed, 93 insertions, 30 deletions
diff --git a/libexec/lfs_cleanerd/cleaner.h b/libexec/lfs_cleanerd/cleaner.h
index a6daf4c3102..9238fa3705d 100644
--- a/libexec/lfs_cleanerd/cleaner.h
+++ b/libexec/lfs_cleanerd/cleaner.h
@@ -69,14 +69,13 @@ int load_segment(struct clfs *, int, BLOCK_INFO **, int *);
int needs_cleaning(struct clfs *, CLEANERINFO *);
int reinit_fs(struct clfs *);
void reload_ifile(struct clfs *);
-void toss_old_blocks(struct clfs *, BLOCK_INFO **, int *, int *);
+void toss_old_blocks(struct clfs *, BLOCK_INFO **, blkcnt_t *, int *);
/* cleansrv.c */
void check_control_socket(void);
void try_to_become_master(int, char **);
/* coalesce.c */
-int log2int(int);
int clean_all_inodes(struct clfs *);
int fork_coalesce(struct clfs *);
diff --git a/libexec/lfs_cleanerd/coalesce.c b/libexec/lfs_cleanerd/coalesce.c
index 37bf0c14f1b..9c5467182ae 100644
--- a/libexec/lfs_cleanerd/coalesce.c
+++ b/libexec/lfs_cleanerd/coalesce.c
@@ -1,4 +1,4 @@
-/* $NetBSD: coalesce.c,v 1.28 2015/07/28 05:14:23 dholland Exp $ */
+/* $NetBSD: coalesce.c,v 1.29 2015/08/12 18:23:16 dholland Exp $ */
/*-
* Copyright (c) 2002, 2005 The NetBSD Foundation, Inc.
@@ -60,7 +60,12 @@
extern int debug, do_mmap;
-int log2int(int n)
+/*
+ * XXX return the arg to just int when/if we don't need it for
+ * potentially huge block counts any more.
+ */
+static int
+log2int(intmax_t n)
{
int log;
@@ -151,8 +156,8 @@ clean_inode(struct clfs *fs, ino_t ino)
int blkcnt;
} */ lim;
daddr_t toff;
- int i;
- int nb, onb, noff;
+ int noff;
+ blkcnt_t i, nb, onb;
int retval;
int bps;
@@ -178,16 +183,36 @@ clean_inode(struct clfs *fs, ino_t ino)
}
#endif
if (nb > dip->di_blocks) {
- dlog("ino %d, computed blocks %d > held blocks %d", ino, nb,
- dip->di_blocks);
+ dlog("ino %ju, computed blocks %jd > held blocks %ju",
+ (uintmax_t)ino, (intmax_t)nb,
+ (uintmax_t)dip->di_blocks);
free(dip);
return COALESCE_BADBLOCKSIZE;
}
+ /*
+ * XXX: We should really coalesce really large files in
+ * chunks, as there's substantial diminishing returns and
+ * mallocing huge amounts of memory just to get those returns
+ * is pretty silly. But that requires a big rework of this
+ * code. (On the plus side though then we can stop worrying
+ * about block counts > 2^31.)
+ */
+
+ /* ugh, no DADDR_T_MAX */
+ __CTASSERT(sizeof(daddr_t) == sizeof(int64_t));
+ if (nb > INT64_MAX / sizeof(BLOCK_INFO)) {
+ syslog(LOG_WARNING, "ino %ju, %jd blocks: array too large\n",
+ (uintmax_t)ino, (uintmax_t)nb);
+ free(dip);
+ return COALESCE_NOMEM;
+ }
+
bip = (BLOCK_INFO *)malloc(sizeof(BLOCK_INFO) * nb);
if (bip == NULL) {
- syslog(LOG_WARNING, "ino %llu, %d blocks: %m",
- (unsigned long long)ino, nb);
+ syslog(LOG_WARNING, "ino %llu, %jd blocks: %s\n",
+ (unsigned long long)ino, (intmax_t)nb,
+ strerror(errno));
free(dip);
return COALESCE_NOMEM;
}
@@ -198,6 +223,18 @@ clean_inode(struct clfs *fs, ino_t ino)
bip[i].bi_version = dip->di_gen;
/* Don't set the size, but let lfs_bmap fill it in */
}
+ /*
+ * The kernel also contains this check; but as lim.blkcnt is
+ * only 32 bits wide, we need to check ourselves too in case
+ * we'd otherwise truncate a value > 2^31, as that might
+ * succeed and create bizarre results.
+ */
+ if (nb > LFS_MARKV_MAXBLKCNT) {
+ syslog(LOG_WARNING, "%s: coalesce: LFCNBMAPV: Too large\n",
+ lfs_sb_getfsmnt(fs));
+ retval = COALESCE_BADBMAPV;
+ goto out;
+ }
lim.blkiov = bip;
lim.blkcnt = nb;
if (kops.ko_fcntl(fs->clfs_ifilefd, LFCNBMAPV, &lim) < 0) {
@@ -208,13 +245,15 @@ clean_inode(struct clfs *fs, ino_t ino)
}
#if 0
for (i = 0; i < nb; i++) {
- printf("bi_size = %d, bi_ino = %d, "
- "bi_lbn = %d, bi_daddr = %d\n",
- bip[i].bi_size, bip[i].bi_inode, bip[i].bi_lbn,
- bip[i].bi_daddr);
+ printf("bi_size = %d, bi_ino = %ju, "
+ "bi_lbn = %jd, bi_daddr = %jd\n",
+ bip[i].bi_size, (uintmax_t)bip[i].bi_inode,
+ (intmax_t)bip[i].bi_lbn,
+ (intmax_t)bip[i].bi_daddr);
}
#endif
- noff = toff = 0;
+ noff = 0;
+ toff = 0;
for (i = 1; i < nb; i++) {
if (bip[i].bi_daddr != bip[i - 1].bi_daddr + lfs_sb_getfrag(fs))
++noff;
@@ -235,8 +274,8 @@ clean_inode(struct clfs *fs, ino_t ino)
goto out;
} else if (debug)
syslog(LOG_DEBUG, "ino %llu total discontinuity "
- "%d (%lld) for %d blocks", (unsigned long long)ino,
- noff, (long long)toff, nb);
+ "%d (%jd) for %jd blocks", (unsigned long long)ino,
+ noff, (intmax_t)toff, (intmax_t)nb);
/* Search for blocks in active segments; don't move them. */
for (i = 0; i < nb; i++) {
@@ -274,8 +313,8 @@ clean_inode(struct clfs *fs, ino_t ino)
for (i = 0; i < nb; i++) {
bip[i].bi_bp = malloc(bip[i].bi_size);
if (bip[i].bi_bp == NULL) {
- syslog(LOG_WARNING, "allocate block buffer size=%d: %m",
- bip[i].bi_size);
+ syslog(LOG_WARNING, "allocate block buffer size=%d: %s\n",
+ bip[i].bi_size, strerror(errno));
retval = COALESCE_NOMEM;
goto out;
}
@@ -287,13 +326,16 @@ clean_inode(struct clfs *fs, ino_t ino)
}
}
if (debug)
- syslog(LOG_DEBUG, "ino %llu markv %d blocks",
- (unsigned long long)ino, nb);
+ syslog(LOG_DEBUG, "ino %ju markv %jd blocks",
+ (uintmax_t)ino, (intmax_t)nb);
/*
* Write in segment-sized chunks. If at any point we'd write more
* than half of the available segments, sleep until that's not
* true any more.
+ *
+ * XXX the pointer arithmetic in this loop is illegal; replace
+ * TBIP with an integer (blkcnt_t) offset.
*/
bps = lfs_segtod(fs, 1);
for (tbip = bip; tbip < bip + nb; tbip += bps) {
@@ -307,6 +349,11 @@ clean_inode(struct clfs *fs, ino_t ino)
LFCNSEGWAIT, NULL);
} while(cip.clean < 4);
+ /*
+ * Note that although lim.blkcnt is 32 bits wide, bps
+ * (which is blocks-per-segment) is < 2^32 so the
+ * value assigned here is always in range.
+ */
lim.blkiov = tbip;
lim.blkcnt = (tbip + bps < bip + nb ? bps : nb % bps);
if (kops.ko_fcntl(fs->clfs_ifilefd, LFCNMARKV, &lim) < 0) {
diff --git a/libexec/lfs_cleanerd/lfs_cleanerd.c b/libexec/lfs_cleanerd/lfs_cleanerd.c
index 4f574e3e535..2918ecc8ee0 100644
--- a/libexec/lfs_cleanerd/lfs_cleanerd.c
+++ b/libexec/lfs_cleanerd/lfs_cleanerd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_cleanerd.c,v 1.44 2015/08/02 18:18:09 dholland Exp $ */
+/* $NetBSD: lfs_cleanerd.c,v 1.45 2015/08/12 18:23:16 dholland Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -791,7 +791,7 @@ bi_comparator(const void *va, const void *vb)
return -1;
if (b->bi_lbn == LFS_UNUSED_LBN)
return 1;
- if ((u_int32_t)a->bi_lbn > (u_int32_t)b->bi_lbn)
+ if ((u_int64_t)a->bi_lbn > (u_int64_t)b->bi_lbn)
return 1;
else
return -1;
@@ -813,9 +813,10 @@ cb_comparator(const void *va, const void *vb)
}
void
-toss_old_blocks(struct clfs *fs, BLOCK_INFO **bipp, int *bic, int *sizep)
+toss_old_blocks(struct clfs *fs, BLOCK_INFO **bipp, blkcnt_t *bic, int *sizep)
{
- int i, r;
+ blkcnt_t i;
+ int r;
BLOCK_INFO *bip = *bipp;
struct lfs_fcntl_markv /* {
BLOCK_INFO *blkiov;
@@ -832,6 +833,13 @@ toss_old_blocks(struct clfs *fs, BLOCK_INFO **bipp, int *bic, int *sizep)
for (i = 0; i < *bic; i++)
bip[i].bi_segcreate = bip[i].bi_daddr;
+ /*
+ * XXX: blkcnt_t is 64 bits, so *bic might overflow size_t
+ * (the argument type of heapsort's number argument) on a
+ * 32-bit platform. However, if so we won't have got this far
+ * because we'll have failed trying to allocate the array. So
+ * while *bic here might cause a 64->32 truncation, it's safe.
+ */
/* Sort the blocks */
heapsort(bip, *bic, sizeof(BLOCK_INFO), bi_comparator);
@@ -870,6 +878,7 @@ invalidate_segment(struct clfs *fs, int sn)
{
BLOCK_INFO *bip;
int i, r, bic;
+ blkcnt_t widebic;
off_t nb;
double util;
struct lfs_fcntl_markv /* {
@@ -884,7 +893,9 @@ invalidate_segment(struct clfs *fs, int sn)
fs->clfs_nactive = 0;
if (load_segment(fs, sn, &bip, &bic) <= 0)
return -1;
- toss_old_blocks(fs, &bip, &bic, NULL);
+ widebic = bic;
+ toss_old_blocks(fs, &bip, &widebic, NULL);
+ bic = widebic;
/* Record statistics */
for (i = nb = 0; i < bic; i++)
@@ -925,7 +936,7 @@ invalidate_segment(struct clfs *fs, int sn)
* if the block needs to be added, 0 if it is already represented.
*/
static int
-check_or_add(ino_t ino, int32_t lbn, BLOCK_INFO *bip, int bic, BLOCK_INFO **ebipp, int *ebicp)
+check_or_add(ino_t ino, daddr_t lbn, BLOCK_INFO *bip, int bic, BLOCK_INFO **ebipp, int *ebicp)
{
BLOCK_INFO *t, *ebip = *ebipp;
int ebic = *ebicp;
@@ -975,7 +986,7 @@ check_hidden_cost(struct clfs *fs, BLOCK_INFO *bip, int bic, off_t *ifc)
int num;
int i, j, ebic;
BLOCK_INFO *ebip;
- int32_t lbn;
+ daddr_t lbn;
start = 0;
ebip = NULL;
@@ -998,6 +1009,7 @@ check_hidden_cost(struct clfs *fs, BLOCK_INFO *bip, int bic, off_t *ifc)
if (bip[i].bi_lbn < ULFS_NDADDR)
continue;
+ /* XXX the struct lfs cast is completely wrong/unsafe */
ulfs_getlbns((struct lfs *)fs, NULL, (daddr_t)bip[i].bi_lbn, in, &num);
for (j = 0; j < num; j++) {
check_or_add(bip[i].bi_inode, in[j].in_lbn,
@@ -1016,6 +1028,7 @@ int
clean_fs(struct clfs *fs, CLEANERINFO *cip)
{
int i, j, ngood, sn, bic, r, npos;
+ blkcnt_t widebic;
int bytes, totbytes;
struct ubuf *bp;
SEGUSE *sup;
@@ -1096,7 +1109,9 @@ clean_fs(struct clfs *fs, CLEANERINFO *cip)
fs->clfs_segtabp[i]->nbytes);
if ((r = load_segment(fs, sn, &bip, &bic)) > 0) {
++ngood;
- toss_old_blocks(fs, &bip, &bic, &bytes);
+ widebic = bic;
+ toss_old_blocks(fs, &bip, &widebic, &bytes);
+ bic = widebic;
totbytes += bytes;
} else if (r == 0)
fd_release(fs->clfs_devvp);
@@ -1124,7 +1139,9 @@ clean_fs(struct clfs *fs, CLEANERINFO *cip)
else
break;
}
- toss_old_blocks(fs, &bip, &bic, NULL);
+ widebic = bic;
+ toss_old_blocks(fs, &bip, &widebic, NULL);
+ bic = widebic;
}
/* If there is nothing to do, try again later. */