Skip to content

Commit

Permalink
Optimize spa_get_random().
Browse files Browse the repository at this point in the history
In all places except two spa_get_random() is used for small values,
and the consumers do not require well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random().

On FreeBSD directly map spa_get_random() to new prng32_bounded() KPI
added in FreeBSD 13.  On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored-By: iXsystems, Inc.
  • Loading branch information
amotin committed Jun 2, 2021
1 parent 8d5f211 commit 14029a0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 23 deletions.
22 changes: 22 additions & 0 deletions include/os/freebsd/spl/sys/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#define _OPENSOLARIS_SYS_RANDOM_H_

#include_next <sys/random.h>
#if __FreeBSD_version >= 1300108
#include <sys/prng.h>
#endif

static inline int
random_get_bytes(uint8_t *p, size_t s)
Expand All @@ -45,4 +48,23 @@ random_get_pseudo_bytes(uint8_t *p, size_t s)
return (0);
}

static inline uint32_t
spa_get_random(uint32_t range)
{
#if __FreeBSD_version >= 1300108
return (prng32_bounded(range));
#else
uint32_t r;

ASSERT(range != 0);

if (range == 1)
return (0);

(void) random_get_pseudo_bytes((void *)&r, sizeof (r));

return (r % range);
#endif
}

#endif /* !_OPENSOLARIS_SYS_RANDOM_H_ */
15 changes: 15 additions & 0 deletions include/os/linux/spl/sys/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,19 @@ random_get_bytes(uint8_t *ptr, size_t len)

extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);

static __inline__ uint32_t
spa_get_random(uint32_t range)
{
uint32_t r;

ASSERT(range != 0);

if (range == 1)
return (0);

(void) random_get_pseudo_bytes((void *)&r, sizeof (r));

return (r % range);
}

#endif /* _SPL_RANDOM_H */
1 change: 0 additions & 1 deletion include/sys/spa.h
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,6 @@ extern spa_t *spa_by_guid(uint64_t pool_guid, uint64_t device_guid);
extern boolean_t spa_guid_exists(uint64_t pool_guid, uint64_t device_guid);
extern char *spa_strdup(const char *);
extern void spa_strfree(char *);
extern uint64_t spa_get_random(uint64_t range);
extern uint64_t spa_generate_guid(spa_t *spa);
extern void snprintf_blkptr(char *buf, size_t buflen, const blkptr_t *bp);
extern void spa_freeze(spa_t *spa);
Expand Down
15 changes: 15 additions & 0 deletions include/sys/zfs_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,21 @@ extern int lowbit64(uint64_t i);
extern int random_get_bytes(uint8_t *ptr, size_t len);
extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);

static __inline__ uint32_t
spa_get_random(uint32_t range)
{
uint32_t r;

ASSERT(range != 0);

if (range == 1)
return (0);

(void) random_get_pseudo_bytes((void *)&r, sizeof (r));

return (r % range);
}

extern void kernel_init(int mode);
extern void kernel_fini(void);
extern void random_init(void);
Expand Down
29 changes: 9 additions & 20 deletions module/zfs/spa_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1494,32 +1494,21 @@ spa_strfree(char *s)
kmem_free(s, strlen(s) + 1);
}

uint64_t
spa_get_random(uint64_t range)
{
uint64_t r;

ASSERT(range != 0);

if (range == 1)
return (0);

(void) random_get_pseudo_bytes((void *)&r, sizeof (uint64_t));

return (r % range);
}

uint64_t
spa_generate_guid(spa_t *spa)
{
uint64_t guid = spa_get_random(-1ULL);
uint64_t guid;

if (spa != NULL) {
while (guid == 0 || spa_guid_exists(spa_guid(spa), guid))
guid = spa_get_random(-1ULL);
do {
(void) random_get_pseudo_bytes((void *)&guid,
sizeof (guid));
} while (guid == 0 || spa_guid_exists(spa_guid(spa), guid));
} else {
while (guid == 0 || spa_guid_exists(guid, 0))
guid = spa_get_random(-1ULL);
do {
(void) random_get_pseudo_bytes((void *)&guid,
sizeof (guid));
} while (guid == 0 || spa_guid_exists(guid, 0));
}

return (guid);
Expand Down
6 changes: 4 additions & 2 deletions module/zfs/zil.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@ zil_init_log_chain(zilog_t *zilog, blkptr_t *bp)
{
zio_cksum_t *zc = &bp->blk_cksum;

zc->zc_word[ZIL_ZC_GUID_0] = spa_get_random(-1ULL);
zc->zc_word[ZIL_ZC_GUID_1] = spa_get_random(-1ULL);
(void) random_get_pseudo_bytes((void *)&zc->zc_word[ZIL_ZC_GUID_0],
sizeof (zc->zc_word[ZIL_ZC_GUID_0]));
(void) random_get_pseudo_bytes((void *)&zc->zc_word[ZIL_ZC_GUID_1],
sizeof (zc->zc_word[ZIL_ZC_GUID_1]));
zc->zc_word[ZIL_ZC_OBJSET] = dmu_objset_id(zilog->zl_os);
zc->zc_word[ZIL_ZC_SEQ] = 1ULL;
}
Expand Down

0 comments on commit 14029a0

Please sign in to comment.