qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename()
@ 2022-09-28 14:41 Bin Meng
  2022-09-28 14:41 ` [PATCH v5 2/2] block: Refactor get_tmp_filename() Bin Meng
  2022-09-29 11:50 ` [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Markus Armbruster
  0 siblings, 2 replies; 7+ messages in thread
From: Bin Meng @ 2022-09-28 14:41 UTC (permalink / raw)
  To: Marc-André Lureau, Daniel P . Berrangé, Markus Armbruster
  Cc: Bin Meng, Hanna Reitz, Kevin Wolf, qemu-block, qemu-devel

From: Bin Meng <bin.meng@windriver.com>

The temporary file has been created and is ready for use. Checking
return value of close() does not seem useful. The file descriptor
is almost certainly closed; see close(2) under "Dealing with error
returns from close()".

Let's simply ignore close() failure here.

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

Changes in v5:
- new patch: "block: Ignore close() failure in get_tmp_filename()"

 block.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/block.c b/block.c
index bc85f46eed..582c205307 100644
--- a/block.c
+++ b/block.c
@@ -886,10 +886,7 @@ int get_tmp_filename(char *filename, int size)
     if (fd < 0) {
         return -errno;
     }
-    if (close(fd) != 0) {
-        unlink(filename);
-        return -errno;
-    }
+    close(fd);
     return 0;
 #endif
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 2/2] block: Refactor get_tmp_filename()
  2022-09-28 14:41 [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Bin Meng
@ 2022-09-28 14:41 ` Bin Meng
  2022-09-29 11:55   ` Markus Armbruster
  2022-09-30 10:13   ` Kevin Wolf
  2022-09-29 11:50 ` [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Markus Armbruster
  1 sibling, 2 replies; 7+ messages in thread
From: Bin Meng @ 2022-09-28 14:41 UTC (permalink / raw)
  To: Marc-André Lureau, Daniel P . Berrangé, Markus Armbruster
  Cc: Bin Meng, Hanna Reitz, Kevin Wolf, qemu-block, qemu-devel

From: Bin Meng <bin.meng@windriver.com>

At present there are two callers of get_tmp_filename() and they are
inconsistent.

One does:

    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
    char *tmp_filename = g_malloc0(PATH_MAX + 1);
    ...
    ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);

while the other does:

    s->qcow_filename = g_malloc(PATH_MAX);
    ret = get_tmp_filename(s->qcow_filename, PATH_MAX);

As we can see different 'size' arguments are passed. There are also
platform specific implementations inside the function, and the use
of snprintf is really undesirable.

The function name is also misleading. It creates a temporary file,
not just a filename.

Refactor this routine by changing its name and signature to:

    char *create_tmp_file(Error **errp)

and use g_file_open_tmp() for a consistent implementation.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

Changes in v5:
- minor change in the commit message
- add some notes in the function comment block
- add g_autofree for tmp_filename

Changes in v4:
- Rename the function to create_tmp_file() and take "Error **errp" as
  a parameter, so that callers can pass errp all the way down to this
  routine.
- Commit message updated to reflect the latest change

Changes in v3:
- Do not use errno directly, instead still let get_tmp_filename() return
  a negative number to indicate error

Changes in v2:
- Use g_autofree and g_steal_pointer

 include/block/block_int-common.h |  2 +-
 block.c                          | 45 ++++++++++++--------------------
 block/vvfat.c                    |  7 +++--
 3 files changed, 20 insertions(+), 34 deletions(-)

diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 8947abab76..d7c0a7e96f 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -1230,7 +1230,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
 }
 
 int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
-int get_tmp_filename(char *filename, int size);
+char *create_tmp_file(Error **errp);
 void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
                                       QDict *options);
 
diff --git a/block.c b/block.c
index 582c205307..bd3006d85d 100644
--- a/block.c
+++ b/block.c
@@ -860,35 +860,25 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 
 /*
  * Create a uniquely-named empty temporary file.
- * Return 0 upon success, otherwise a negative errno value.
+ * Return the actual file name used upon success, otherwise NULL.
+ * This string should be freed with g_free() when not needed any longer.
+ *
+ * Note: creating a temporary file for the caller to (re)open is
+ * inherently racy. Use g_file_open_tmp() instead whenever practical.
  */
-int get_tmp_filename(char *filename, int size)
+char *create_tmp_file(Error **errp)
 {
-#ifdef _WIN32
-    char temp_dir[MAX_PATH];
-    /* GetTempFileName requires that its output buffer (4th param)
-       have length MAX_PATH or greater.  */
-    assert(size >= MAX_PATH);
-    return (GetTempPath(MAX_PATH, temp_dir)
-            && GetTempFileName(temp_dir, "qem", 0, filename)
-            ? 0 : -GetLastError());
-#else
+    g_autofree char *name = NULL;
+    g_autoptr(GError) err = NULL;
     int fd;
-    const char *tmpdir;
-    tmpdir = getenv("TMPDIR");
-    if (!tmpdir) {
-        tmpdir = "/var/tmp";
-    }
-    if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
-        return -EOVERFLOW;
-    }
-    fd = mkstemp(filename);
+
+    fd = g_file_open_tmp("vl.XXXXXX", &name, &err);
     if (fd < 0) {
-        return -errno;
+        error_setg(errp, "%s", err->message);
+        return NULL;
     }
     close(fd);
-    return 0;
-#endif
+    return g_steal_pointer(&name);
 }
 
 /*
@@ -3714,8 +3704,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
                                                    QDict *snapshot_options,
                                                    Error **errp)
 {
-    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
-    char *tmp_filename = g_malloc0(PATH_MAX + 1);
+    g_autofree char *tmp_filename = NULL;
     int64_t total_size;
     QemuOpts *opts = NULL;
     BlockDriverState *bs_snapshot = NULL;
@@ -3734,9 +3723,8 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
     }
 
     /* Create the temporary image */
-    ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "Could not get temporary filename");
+    tmp_filename = create_tmp_file(errp);
+    if (!tmp_filename) {
         goto out;
     }
 
@@ -3770,7 +3758,6 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
 
 out:
     qobject_unref(snapshot_options);
-    g_free(tmp_filename);
     return bs_snapshot;
 }
 
diff --git a/block/vvfat.c b/block/vvfat.c
index d6dd919683..f9bf8406d3 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3146,10 +3146,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
 
     array_init(&(s->commits), sizeof(commit_t));
 
-    s->qcow_filename = g_malloc(PATH_MAX);
-    ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "can't create temporary file");
+    s->qcow_filename = create_tmp_file(errp);
+    if (!s->qcow_filename) {
+        ret = -ENOENT;
         goto err;
     }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename()
  2022-09-28 14:41 [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Bin Meng
  2022-09-28 14:41 ` [PATCH v5 2/2] block: Refactor get_tmp_filename() Bin Meng
@ 2022-09-29 11:50 ` Markus Armbruster
  1 sibling, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2022-09-29 11:50 UTC (permalink / raw)
  To: Bin Meng
  Cc: Marc-André Lureau, Daniel P . Berrangé,
	Bin Meng, Hanna Reitz, Kevin Wolf, qemu-block, qemu-devel

Bin Meng <bmeng.cn@gmail.com> writes:

> From: Bin Meng <bin.meng@windriver.com>
>
> The temporary file has been created and is ready for use. Checking
> return value of close() does not seem useful. The file descriptor
> is almost certainly closed; see close(2) under "Dealing with error
> returns from close()".
>
> Let's simply ignore close() failure here.
>
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> ---
>
> Changes in v5:
> - new patch: "block: Ignore close() failure in get_tmp_filename()"
>
>  block.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/block.c b/block.c
> index bc85f46eed..582c205307 100644
> --- a/block.c
> +++ b/block.c
> @@ -886,10 +886,7 @@ int get_tmp_filename(char *filename, int size)
>      if (fd < 0) {
>          return -errno;
>      }
> -    if (close(fd) != 0) {
> -        unlink(filename);
> -        return -errno;
> -    }
> +    close(fd);
>      return 0;
>  #endif
>  }

Reviewed-by: Markus Armbruster <armbru@redhat.com>



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 2/2] block: Refactor get_tmp_filename()
  2022-09-28 14:41 ` [PATCH v5 2/2] block: Refactor get_tmp_filename() Bin Meng
@ 2022-09-29 11:55   ` Markus Armbruster
  2022-09-30 10:13   ` Kevin Wolf
  1 sibling, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2022-09-29 11:55 UTC (permalink / raw)
  To: Bin Meng
  Cc: Marc-André Lureau, Daniel P . Berrangé,
	Bin Meng, Hanna Reitz, Kevin Wolf, qemu-block, qemu-devel

Bin Meng <bmeng.cn@gmail.com> writes:

> From: Bin Meng <bin.meng@windriver.com>
>
> At present there are two callers of get_tmp_filename() and they are
> inconsistent.
>
> One does:
>
>     /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
>     char *tmp_filename = g_malloc0(PATH_MAX + 1);
>     ...
>     ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
>
> while the other does:
>
>     s->qcow_filename = g_malloc(PATH_MAX);
>     ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
>
> As we can see different 'size' arguments are passed. There are also
> platform specific implementations inside the function, and the use
> of snprintf is really undesirable.
>
> The function name is also misleading. It creates a temporary file,
> not just a filename.
>
> Refactor this routine by changing its name and signature to:
>
>     char *create_tmp_file(Error **errp)
>
> and use g_file_open_tmp() for a consistent implementation.
>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 2/2] block: Refactor get_tmp_filename()
  2022-09-28 14:41 ` [PATCH v5 2/2] block: Refactor get_tmp_filename() Bin Meng
  2022-09-29 11:55   ` Markus Armbruster
@ 2022-09-30 10:13   ` Kevin Wolf
  2022-10-02  9:38     ` Bin Meng
  1 sibling, 1 reply; 7+ messages in thread
From: Kevin Wolf @ 2022-09-30 10:13 UTC (permalink / raw)
  To: Bin Meng
  Cc: Marc-André Lureau, Daniel P . Berrangé,
	Markus Armbruster, Bin Meng, Hanna Reitz, qemu-block, qemu-devel

Am 28.09.2022 um 16:41 hat Bin Meng geschrieben:
> From: Bin Meng <bin.meng@windriver.com>
> 
> At present there are two callers of get_tmp_filename() and they are
> inconsistent.
> 
> One does:
> 
>     /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
>     char *tmp_filename = g_malloc0(PATH_MAX + 1);
>     ...
>     ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
> 
> while the other does:
> 
>     s->qcow_filename = g_malloc(PATH_MAX);
>     ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
> 
> As we can see different 'size' arguments are passed. There are also
> platform specific implementations inside the function, and the use
> of snprintf is really undesirable.
> 
> The function name is also misleading. It creates a temporary file,
> not just a filename.
> 
> Refactor this routine by changing its name and signature to:
> 
>     char *create_tmp_file(Error **errp)
> 
> and use g_file_open_tmp() for a consistent implementation.
> 
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> ---
> 
> Changes in v5:
> - minor change in the commit message
> - add some notes in the function comment block
> - add g_autofree for tmp_filename
> 
> Changes in v4:
> - Rename the function to create_tmp_file() and take "Error **errp" as
>   a parameter, so that callers can pass errp all the way down to this
>   routine.
> - Commit message updated to reflect the latest change
> 
> Changes in v3:
> - Do not use errno directly, instead still let get_tmp_filename() return
>   a negative number to indicate error
> 
> Changes in v2:
> - Use g_autofree and g_steal_pointer
> 
>  include/block/block_int-common.h |  2 +-
>  block.c                          | 45 ++++++++++++--------------------
>  block/vvfat.c                    |  7 +++--
>  3 files changed, 20 insertions(+), 34 deletions(-)
> 
> diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
> index 8947abab76..d7c0a7e96f 100644
> --- a/include/block/block_int-common.h
> +++ b/include/block/block_int-common.h
> @@ -1230,7 +1230,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
>  }
>  
>  int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
> -int get_tmp_filename(char *filename, int size);
> +char *create_tmp_file(Error **errp);
>  void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
>                                        QDict *options);
>  
> diff --git a/block.c b/block.c
> index 582c205307..bd3006d85d 100644
> --- a/block.c
> +++ b/block.c
> @@ -860,35 +860,25 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
>  
>  /*
>   * Create a uniquely-named empty temporary file.
> - * Return 0 upon success, otherwise a negative errno value.
> + * Return the actual file name used upon success, otherwise NULL.
> + * This string should be freed with g_free() when not needed any longer.
> + *
> + * Note: creating a temporary file for the caller to (re)open is
> + * inherently racy. Use g_file_open_tmp() instead whenever practical.
>   */
> -int get_tmp_filename(char *filename, int size)
> +char *create_tmp_file(Error **errp)
>  {
> -#ifdef _WIN32
> -    char temp_dir[MAX_PATH];
> -    /* GetTempFileName requires that its output buffer (4th param)
> -       have length MAX_PATH or greater.  */
> -    assert(size >= MAX_PATH);
> -    return (GetTempPath(MAX_PATH, temp_dir)
> -            && GetTempFileName(temp_dir, "qem", 0, filename)

We're using different prefixes on Windows and on Linux. This patch
unifies both paths to use the Linux name. Nobody should rely on the name
of temporary files, so there is hope it won't break anything.

> -            ? 0 : -GetLastError());
> -#else
> +    g_autofree char *name = NULL;
> +    g_autoptr(GError) err = NULL;
>      int fd;
> -    const char *tmpdir;
> -    tmpdir = getenv("TMPDIR");
> -    if (!tmpdir) {
> -        tmpdir = "/var/tmp";
> -    }
> -    if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
> -        return -EOVERFLOW;
> -    }
> -    fd = mkstemp(filename);
> +
> +    fd = g_file_open_tmp("vl.XXXXXX", &name, &err);

This implicitly reverts commit 69bef7931e8, g_file_open_tmp() uses /tmp
as the default instead of /var/tmp as this function does before the
patch.

This is probably not a good idea, we should keep the /var/tmp default.

But if we did want to do this, it's definitely a change in behaviour
that should be mentioned in the commit message at least.

Kevin



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 2/2] block: Refactor get_tmp_filename()
  2022-09-30 10:13   ` Kevin Wolf
@ 2022-10-02  9:38     ` Bin Meng
  2022-10-04  8:48       ` Kevin Wolf
  0 siblings, 1 reply; 7+ messages in thread
From: Bin Meng @ 2022-10-02  9:38 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Marc-André Lureau, Daniel P . Berrangé,
	Markus Armbruster, Bin Meng, Hanna Reitz, qemu-block, qemu-devel

Hi Kevin,

On Fri, Sep 30, 2022 at 6:13 PM Kevin Wolf <kwolf@redhat.com> wrote:
>
> Am 28.09.2022 um 16:41 hat Bin Meng geschrieben:
> > From: Bin Meng <bin.meng@windriver.com>
> >
> > At present there are two callers of get_tmp_filename() and they are
> > inconsistent.
> >
> > One does:
> >
> >     /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
> >     char *tmp_filename = g_malloc0(PATH_MAX + 1);
> >     ...
> >     ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
> >
> > while the other does:
> >
> >     s->qcow_filename = g_malloc(PATH_MAX);
> >     ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
> >
> > As we can see different 'size' arguments are passed. There are also
> > platform specific implementations inside the function, and the use
> > of snprintf is really undesirable.
> >
> > The function name is also misleading. It creates a temporary file,
> > not just a filename.
> >
> > Refactor this routine by changing its name and signature to:
> >
> >     char *create_tmp_file(Error **errp)
> >
> > and use g_file_open_tmp() for a consistent implementation.
> >
> > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> > ---
> >
> > Changes in v5:
> > - minor change in the commit message
> > - add some notes in the function comment block
> > - add g_autofree for tmp_filename
> >
> > Changes in v4:
> > - Rename the function to create_tmp_file() and take "Error **errp" as
> >   a parameter, so that callers can pass errp all the way down to this
> >   routine.
> > - Commit message updated to reflect the latest change
> >
> > Changes in v3:
> > - Do not use errno directly, instead still let get_tmp_filename() return
> >   a negative number to indicate error
> >
> > Changes in v2:
> > - Use g_autofree and g_steal_pointer
> >
> >  include/block/block_int-common.h |  2 +-
> >  block.c                          | 45 ++++++++++++--------------------
> >  block/vvfat.c                    |  7 +++--
> >  3 files changed, 20 insertions(+), 34 deletions(-)
> >
> > diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
> > index 8947abab76..d7c0a7e96f 100644
> > --- a/include/block/block_int-common.h
> > +++ b/include/block/block_int-common.h
> > @@ -1230,7 +1230,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
> >  }
> >
> >  int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
> > -int get_tmp_filename(char *filename, int size);
> > +char *create_tmp_file(Error **errp);
> >  void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
> >                                        QDict *options);
> >
> > diff --git a/block.c b/block.c
> > index 582c205307..bd3006d85d 100644
> > --- a/block.c
> > +++ b/block.c
> > @@ -860,35 +860,25 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
> >
> >  /*
> >   * Create a uniquely-named empty temporary file.
> > - * Return 0 upon success, otherwise a negative errno value.
> > + * Return the actual file name used upon success, otherwise NULL.
> > + * This string should be freed with g_free() when not needed any longer.
> > + *
> > + * Note: creating a temporary file for the caller to (re)open is
> > + * inherently racy. Use g_file_open_tmp() instead whenever practical.
> >   */
> > -int get_tmp_filename(char *filename, int size)
> > +char *create_tmp_file(Error **errp)
> >  {
> > -#ifdef _WIN32
> > -    char temp_dir[MAX_PATH];
> > -    /* GetTempFileName requires that its output buffer (4th param)
> > -       have length MAX_PATH or greater.  */
> > -    assert(size >= MAX_PATH);
> > -    return (GetTempPath(MAX_PATH, temp_dir)
> > -            && GetTempFileName(temp_dir, "qem", 0, filename)
>
> We're using different prefixes on Windows and on Linux. This patch
> unifies both paths to use the Linux name. Nobody should rely on the name
> of temporary files, so there is hope it won't break anything.
>
> > -            ? 0 : -GetLastError());
> > -#else
> > +    g_autofree char *name = NULL;
> > +    g_autoptr(GError) err = NULL;
> >      int fd;
> > -    const char *tmpdir;
> > -    tmpdir = getenv("TMPDIR");
> > -    if (!tmpdir) {
> > -        tmpdir = "/var/tmp";
> > -    }
> > -    if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
> > -        return -EOVERFLOW;
> > -    }
> > -    fd = mkstemp(filename);
> > +
> > +    fd = g_file_open_tmp("vl.XXXXXX", &name, &err);
>
> This implicitly reverts commit 69bef7931e8, g_file_open_tmp() uses /tmp
> as the default instead of /var/tmp as this function does before the
> patch.

Oops, thanks for the pointer. Commit message of 69bef7931e8 does not
explicitely explain why to change from /tmp to /var/tmp. Is that
because QEMU block codes write a huge size of data to this file in
/tmp?

> This is probably not a good idea, we should keep the /var/tmp default.
>
> But if we did want to do this, it's definitely a change in behaviour
> that should be mentioned in the commit message at least.
>

If we have to keep /var/tmp, how about this?

diff --git a/block.c b/block.c
index bd3006d85d..d964ceaeac 100644
--- a/block.c
+++ b/block.c
@@ -24,6 +24,7 @@
  */

 #include "qemu/osdep.h"
+#include <glib/gstdio.h>
 #include "block/trace.h"
 #include "block/block_int.h"
 #include "block/blockjob.h"
@@ -878,7 +879,20 @@ char *create_tmp_file(Error **errp)
         return NULL;
     }
     close(fd);
+#ifdef _WIN32
     return g_steal_pointer(&name);
+#else
+    g_autofree char *base = NULL;
+    char *newname;
+
+    base = g_path_get_basename(name);
+    newname = g_strdup_printf("/var/tmp/%s", base);
+    if (g_rename(name, newname) < 0) {
+        error_setg_errno(errp, -errno, "Could not create file");
+        return NULL;
+    }
+    return newname;
+#endif
 }

Regards,
Bin


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 2/2] block: Refactor get_tmp_filename()
  2022-10-02  9:38     ` Bin Meng
@ 2022-10-04  8:48       ` Kevin Wolf
  0 siblings, 0 replies; 7+ messages in thread
From: Kevin Wolf @ 2022-10-04  8:48 UTC (permalink / raw)
  To: Bin Meng
  Cc: Marc-André Lureau, Daniel P . Berrangé,
	Markus Armbruster, Bin Meng, Hanna Reitz, qemu-block, qemu-devel

Am 02.10.2022 um 11:38 hat Bin Meng geschrieben:
> Hi Kevin,
> 
> On Fri, Sep 30, 2022 at 6:13 PM Kevin Wolf <kwolf@redhat.com> wrote:
> >
> > Am 28.09.2022 um 16:41 hat Bin Meng geschrieben:
> > > From: Bin Meng <bin.meng@windriver.com>
> > >
> > > At present there are two callers of get_tmp_filename() and they are
> > > inconsistent.
> > >
> > > One does:
> > >
> > >     /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
> > >     char *tmp_filename = g_malloc0(PATH_MAX + 1);
> > >     ...
> > >     ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
> > >
> > > while the other does:
> > >
> > >     s->qcow_filename = g_malloc(PATH_MAX);
> > >     ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
> > >
> > > As we can see different 'size' arguments are passed. There are also
> > > platform specific implementations inside the function, and the use
> > > of snprintf is really undesirable.
> > >
> > > The function name is also misleading. It creates a temporary file,
> > > not just a filename.
> > >
> > > Refactor this routine by changing its name and signature to:
> > >
> > >     char *create_tmp_file(Error **errp)
> > >
> > > and use g_file_open_tmp() for a consistent implementation.
> > >
> > > Signed-off-by: Bin Meng <bin.meng@windriver.com>
> > > ---
> > >
> > > Changes in v5:
> > > - minor change in the commit message
> > > - add some notes in the function comment block
> > > - add g_autofree for tmp_filename
> > >
> > > Changes in v4:
> > > - Rename the function to create_tmp_file() and take "Error **errp" as
> > >   a parameter, so that callers can pass errp all the way down to this
> > >   routine.
> > > - Commit message updated to reflect the latest change
> > >
> > > Changes in v3:
> > > - Do not use errno directly, instead still let get_tmp_filename() return
> > >   a negative number to indicate error
> > >
> > > Changes in v2:
> > > - Use g_autofree and g_steal_pointer
> > >
> > >  include/block/block_int-common.h |  2 +-
> > >  block.c                          | 45 ++++++++++++--------------------
> > >  block/vvfat.c                    |  7 +++--
> > >  3 files changed, 20 insertions(+), 34 deletions(-)
> > >
> > > diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
> > > index 8947abab76..d7c0a7e96f 100644
> > > --- a/include/block/block_int-common.h
> > > +++ b/include/block/block_int-common.h
> > > @@ -1230,7 +1230,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
> > >  }
> > >
> > >  int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
> > > -int get_tmp_filename(char *filename, int size);
> > > +char *create_tmp_file(Error **errp);
> > >  void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
> > >                                        QDict *options);
> > >
> > > diff --git a/block.c b/block.c
> > > index 582c205307..bd3006d85d 100644
> > > --- a/block.c
> > > +++ b/block.c
> > > @@ -860,35 +860,25 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
> > >
> > >  /*
> > >   * Create a uniquely-named empty temporary file.
> > > - * Return 0 upon success, otherwise a negative errno value.
> > > + * Return the actual file name used upon success, otherwise NULL.
> > > + * This string should be freed with g_free() when not needed any longer.
> > > + *
> > > + * Note: creating a temporary file for the caller to (re)open is
> > > + * inherently racy. Use g_file_open_tmp() instead whenever practical.
> > >   */
> > > -int get_tmp_filename(char *filename, int size)
> > > +char *create_tmp_file(Error **errp)
> > >  {
> > > -#ifdef _WIN32
> > > -    char temp_dir[MAX_PATH];
> > > -    /* GetTempFileName requires that its output buffer (4th param)
> > > -       have length MAX_PATH or greater.  */
> > > -    assert(size >= MAX_PATH);
> > > -    return (GetTempPath(MAX_PATH, temp_dir)
> > > -            && GetTempFileName(temp_dir, "qem", 0, filename)
> >
> > We're using different prefixes on Windows and on Linux. This patch
> > unifies both paths to use the Linux name. Nobody should rely on the name
> > of temporary files, so there is hope it won't break anything.
> >
> > > -            ? 0 : -GetLastError());
> > > -#else
> > > +    g_autofree char *name = NULL;
> > > +    g_autoptr(GError) err = NULL;
> > >      int fd;
> > > -    const char *tmpdir;
> > > -    tmpdir = getenv("TMPDIR");
> > > -    if (!tmpdir) {
> > > -        tmpdir = "/var/tmp";
> > > -    }
> > > -    if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
> > > -        return -EOVERFLOW;
> > > -    }
> > > -    fd = mkstemp(filename);
> > > +
> > > +    fd = g_file_open_tmp("vl.XXXXXX", &name, &err);
> >
> > This implicitly reverts commit 69bef7931e8, g_file_open_tmp() uses /tmp
> > as the default instead of /var/tmp as this function does before the
> > patch.
> 
> Oops, thanks for the pointer. Commit message of 69bef7931e8 does not
> explicitely explain why to change from /tmp to /var/tmp. Is that
> because QEMU block codes write a huge size of data to this file in
> /tmp?

Yes, this function is used to create temporary disk images (like for
-snapshot), so the files can become very large. /tmp is often a tmpfs
where as /var/tmp is usually on a disk, so more appropriate for disk
images.

> > This is probably not a good idea, we should keep the /var/tmp default.
> >
> > But if we did want to do this, it's definitely a change in behaviour
> > that should be mentioned in the commit message at least.
> >
> 
> If we have to keep /var/tmp, how about this?
> 
> diff --git a/block.c b/block.c
> index bd3006d85d..d964ceaeac 100644
> --- a/block.c
> +++ b/block.c
> @@ -24,6 +24,7 @@
>   */
> 
>  #include "qemu/osdep.h"
> +#include <glib/gstdio.h>
>  #include "block/trace.h"
>  #include "block/block_int.h"
>  #include "block/blockjob.h"
> @@ -878,7 +879,20 @@ char *create_tmp_file(Error **errp)
>          return NULL;
>      }
>      close(fd);
> +#ifdef _WIN32
>      return g_steal_pointer(&name);
> +#else
> +    g_autofree char *base = NULL;
> +    char *newname;
> +
> +    base = g_path_get_basename(name);
> +    newname = g_strdup_printf("/var/tmp/%s", base);
> +    if (g_rename(name, newname) < 0) {
> +        error_setg_errno(errp, -errno, "Could not create file");
> +        return NULL;
> +    }
> +    return newname;
> +#endif
>  }

I don't think this works correctly. It first finds an unused filename in
/tmp, and then uses that filename in /var/tmp without checking if it's
already in use there. It's also not simpler than the original code.

We should probably stick with g_mkstemp(), which however can be shared
between Windows and Linux. Just finding the directory is still going to
use an #ifdef.

But the more important point of your patch was the external interface of
the function anyway, and you can keep that as it is.

Kevin



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-10-04  8:55 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-28 14:41 [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Bin Meng
2022-09-28 14:41 ` [PATCH v5 2/2] block: Refactor get_tmp_filename() Bin Meng
2022-09-29 11:55   ` Markus Armbruster
2022-09-30 10:13   ` Kevin Wolf
2022-10-02  9:38     ` Bin Meng
2022-10-04  8:48       ` Kevin Wolf
2022-09-29 11:50 ` [PATCH v5 1/2] block: Ignore close() failure in get_tmp_filename() Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).