diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 1336d282..7c676f4c 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1536,30 +1536,6 @@ devino_cache_lookup (OstreeRepo *self, return dev_ino_val->checksum; } -static gboolean -min_free_space_calculate_reserved_blocks (OstreeRepo *self, struct statvfs *stvfsbuf, GError **error) -{ - self->reserved_blocks = 0; - - if (self->min_free_space_mb > 0) - { - if (self->min_free_space_mb > (G_MAXUINT64 >> 20) || - self->txn.blocksize > (1 << 20)) - return glnx_throw (error, "min-free-space value is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", - G_MAXUINT64 / stvfsbuf->f_bsize); - - self->reserved_blocks = (self->min_free_space_mb << 20) / self->txn.blocksize; - } - else if (self->min_free_space_percent > 0) - { - /* Convert fragment to blocks to compute the total */ - guint64 total_blocks = (stvfsbuf->f_frsize * stvfsbuf->f_blocks) / stvfsbuf->f_bsize; - self->reserved_blocks = ((double)total_blocks) * (self->min_free_space_percent/100.0); - } - - return TRUE; -} - /** * ostree_repo_scan_hardlinks: * @self: An #OstreeRepo @@ -1631,6 +1607,7 @@ ostree_repo_prepare_transaction (OstreeRepo *self, GError **error) { g_autoptr(_OstreeRepoAutoTransaction) txn = NULL; + guint64 reserved_bytes = 0; g_return_val_if_fail (self->in_transaction == FALSE, FALSE); @@ -1655,11 +1632,12 @@ ostree_repo_prepare_transaction (OstreeRepo *self, g_mutex_lock (&self->txn_lock); self->txn.blocksize = stvfsbuf.f_bsize; - if (!min_free_space_calculate_reserved_blocks (self, &stvfsbuf, error)) + if (!ostree_repo_get_min_free_space_bytes (self, &reserved_bytes, error)) { g_mutex_unlock (&self->txn_lock); return FALSE; } + self->reserved_blocks = reserved_bytes / self->txn.blocksize; /* Use the appropriate free block count if we're unprivileged */ guint64 bfree = (getuid () != 0 ? stvfsbuf.f_bavail : stvfsbuf.f_bfree); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 264a2e57..5c8f0b6f 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -2655,6 +2655,37 @@ get_remotes_d_dir (OstreeRepo *self, return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES); } +static gboolean +min_free_space_calculate_reserved_bytes (OstreeRepo *self, guint64 *bytes, GError **error) +{ + guint64 reserved_bytes = 0; + + struct statvfs stvfsbuf; + if (TEMP_FAILURE_RETRY (fstatvfs (self->repo_dir_fd, &stvfsbuf)) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + + if (self->min_free_space_mb > 0) + { + if (self->min_free_space_mb > (G_MAXUINT64 >> 20)) + return glnx_throw (error, "min-free-space value is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", + (G_MAXUINT64 >> 20)); + + reserved_bytes = self->min_free_space_mb << 20; + } + else if (self->min_free_space_percent > 0) + { + if (stvfsbuf.f_frsize > (G_MAXUINT64 / stvfsbuf.f_blocks)) + return glnx_throw (error, "Filesystem's size is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", + (G_MAXUINT64 / stvfsbuf.f_blocks)); + + guint64 total_bytes = (stvfsbuf.f_frsize * stvfsbuf.f_blocks); + reserved_bytes = ((double)total_bytes) * (self->min_free_space_percent/100.0); + } + + *bytes = reserved_bytes; + return TRUE; +} + static gboolean min_free_space_size_validate_and_convert (OstreeRepo *self, const char *min_free_space_size_str, @@ -3297,21 +3328,25 @@ ostree_repo_get_mode (OstreeRepo *self) /** * ostree_repo_get_min_free_space: * @self: Repo + * @out_reserved_bytes: (out): Location to store the result + * @error: Return location for a #GError * - * It should be noted that this function should be used only if there - * is a transaction active. It is a programmer error to request it - * otherwise. + * It can be used to query the value (in bytes) of min-free-space-* config option. * - * Returns: Value (in bytes) of min-free-space-* config option + * Returns: %TRUE on success, %FALSE otherwise. * Since: 2018.9 */ -guint64 -ostree_repo_get_min_free_space_bytes (OstreeRepo *self) +gboolean +ostree_repo_get_min_free_space_bytes (OstreeRepo *self, guint64 *out_reserved_bytes, GError **error) { - g_return_val_if_fail (OSTREE_IS_REPO (self), 0); - g_return_val_if_fail (self->in_transaction == TRUE, 0); + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (out_reserved_bytes != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return self->reserved_blocks * self->txn.blocksize; + if (!min_free_space_calculate_reserved_bytes (self, out_reserved_bytes, error)) + return glnx_prefix_error (error, "Error calculating min-free-space bytes"); + + return TRUE; } /** diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 6159fc24..a6544761 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -128,7 +128,9 @@ _OSTREE_PUBLIC OstreeRepoMode ostree_repo_get_mode (OstreeRepo *self); _OSTREE_PUBLIC -guint64 ostree_repo_get_min_free_space_bytes (OstreeRepo *self); +gboolean ostree_repo_get_min_free_space_bytes (OstreeRepo *self, + guint64 *out_reserved_bytes, + GError **error); _OSTREE_PUBLIC GKeyFile * ostree_repo_get_config (OstreeRepo *self);