lib/repo: Separate min-free-space-* calculation from transaction codepath
authorUmang Jain <umang@endlessm.com>
Thu, 13 Sep 2018 19:37:32 +0000 (01:07 +0530)
committerAtomic Bot <atomic-devel@projectatomic.io>
Fri, 21 Sep 2018 15:09:12 +0000 (15:09 +0000)
Earlier, the actual reserved space (in blocks) were calculated inside the
transaction codepath ostree_repo_prepare_transaction(). However, while
reworking on ostree_repo_get_min_free_space_bytes() API, it was realized that
this calculation can be done independently from the transaction's codepaths, hence
enabling the usage for ostree_repo_get_min_free_space_bytes() API irrespective
of whether there is an ongoing transaction or not.

https://github.com/ostreedev/ostree/issues/1720

Closes: #1722
Approved by: pwithnall

src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo.c
src/libostree/ostree-repo.h

index 1336d28239128acf0917ffd547d2d07828caa364..7c676f4c5a1c54cd3b76b8a7ac9f2e751bbf71dd 100644 (file)
@@ -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);
index 264a2e57677dec1d67490ad45c69173f00ea8339..5c8f0b6f12eba9d5da4129260468783fdb20d2fd 100644 (file)
@@ -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;
 }
 
 /**
index 6159fc244eb5d0c7f721481d17b6980976f3d536..a65447615e54e259053052e8c571378840066e24 100644 (file)
@@ -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);