Patchwork [v4,rebased] block: more read-only changes, related to backing files

login
register
mail settings
Submitter Naphtali Sprei
Date Feb. 14, 2010, 11:39 a.m.
Message ID <4B77E0E6.1090701@redhat.com>
Download mbox | patch
Permalink /patch/45293/
State New
Headers show

Comments

Naphtali Sprei - Feb. 14, 2010, 11:39 a.m.
Open backing file read-only where possible
Upgrade backing file to read-write during commit, back to read-only after commit
  If upgrade fail, back to read-only. If also fail, "disconnect" the drive.

Signed-off-by: Naphtali Sprei <nsprei@redhat.com>
---
 block.c     |   83 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 block_int.h |    2 +
 2 files changed, 73 insertions(+), 12 deletions(-)
Anthony Liguori - Feb. 19, 2010, 9:48 p.m.
On 02/14/2010 05:39 AM, Naphtali Sprei wrote:
> Open backing file read-only where possible
> Upgrade backing file to read-write during commit, back to read-only after commit
>    If upgrade fail, back to read-only. If also fail, "disconnect" the drive.
>
> Signed-off-by: Naphtali Sprei<nsprei@redhat.com>
>    

Applied.  Thanks.

Regards,

Anthony Liguori
> ---
>   block.c     |   83 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
>   block_int.h |    2 +
>   2 files changed, 73 insertions(+), 12 deletions(-)
>
> diff --git a/block.c b/block.c
> index af56ea7..31d1ba4 100644
> --- a/block.c
> +++ b/block.c
> @@ -363,6 +363,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
>       bs->is_temporary = 0;
>       bs->encrypted = 0;
>       bs->valid_key = 0;
> +    bs->open_flags = flags;
>       /* buffer_alignment defaulted to 512, drivers can change this value */
>       bs->buffer_alignment = 512;
>
> @@ -450,8 +451,6 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
>       if (flags&  (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
>           bs->enable_write_cache = 1;
>
> -    bs->read_only = (flags&  BDRV_O_RDWR) == 0;
> -
>       /*
>        * Clear flags that are internal to the block layer before opening the
>        * image.
> @@ -472,6 +471,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
>           goto free_and_fail;
>       }
>
> +    bs->keep_read_only = bs->read_only = !(open_flags&  BDRV_O_RDWR);
>       if (drv->bdrv_getlength) {
>           bs->total_sectors = bdrv_getlength(bs)>>  BDRV_SECTOR_BITS;
>       }
> @@ -488,13 +488,22 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
>                        filename, bs->backing_file);
>           if (bs->backing_format[0] != '\0')
>               back_drv = bdrv_find_format(bs->backing_format);
> +
> +        /* backing files always opened read-only */
> +        open_flags&= ~BDRV_O_RDWR;
> +
>           ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
>                            back_drv);
> -        bs->backing_hd->read_only =  (open_flags&  BDRV_O_RDWR) == 0;
>           if (ret<  0) {
>               bdrv_close(bs);
>               return ret;
>           }
> +        if (bs->is_temporary) {
> +            bs->backing_hd->keep_read_only = !(flags&  BDRV_O_RDWR);
> +        } else {
> +            /* base image inherits from "parent" */
> +            bs->backing_hd->keep_read_only = bs->keep_read_only;
> +        }
>       }
>
>       if (!bdrv_key_required(bs)) {
> @@ -570,19 +579,48 @@ int bdrv_commit(BlockDriverState *bs)
>   {
>       BlockDriver *drv = bs->drv;
>       int64_t i, total_sectors;
> -    int n, j;
> -    int ret = 0;
> +    int n, j, ro, open_flags;
> +    int ret = 0, rw_ret = 0;
>       unsigned char sector[512];
> +    char filename[1024];
> +    BlockDriverState *bs_rw, *bs_ro;
>
>       if (!drv)
>           return -ENOMEDIUM;
> -
> -    if (bs->read_only) {
> -	return -EACCES;
> +
> +    if (!bs->backing_hd) {
> +        return -ENOTSUP;
>       }
>
> -    if (!bs->backing_hd) {
> -	return -ENOTSUP;
> +    if (bs->backing_hd->keep_read_only) {
> +        return -EACCES;
> +    }
> +
> +    ro = bs->backing_hd->read_only;
> +    strncpy(filename, bs->backing_hd->filename, sizeof(filename));
> +    open_flags =  bs->backing_hd->open_flags;
> +
> +    if (ro) {
> +        /* re-open as RW */
> +        bdrv_delete(bs->backing_hd);
> +        bs->backing_hd = NULL;
> +        bs_rw = bdrv_new("");
> +        rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL);
> +        if (rw_ret<  0) {
> +            bdrv_delete(bs_rw);
> +            /* try to re-open read-only */
> +            bs_ro = bdrv_new("");
> +            ret = bdrv_open2(bs_ro, filename, open_flags&  ~BDRV_O_RDWR, NULL);
> +            if (ret<  0) {
> +                bdrv_delete(bs_ro);
> +                /* drive not functional anymore */
> +                bs->drv = NULL;
> +                return ret;
> +            }
> +            bs->backing_hd = bs_ro;
> +            return rw_ret;
> +        }
> +        bs->backing_hd = bs_rw;
>       }
>
>       total_sectors = bdrv_getlength(bs)>>  BDRV_SECTOR_BITS;
> @@ -590,11 +628,13 @@ int bdrv_commit(BlockDriverState *bs)
>           if (drv->bdrv_is_allocated(bs, i, 65536,&n)) {
>               for(j = 0; j<  n; j++) {
>                   if (bdrv_read(bs, i, sector, 1) != 0) {
> -                    return -EIO;
> +                    ret = -EIO;
> +                    goto ro_cleanup;
>                   }
>
>                   if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
> -                    return -EIO;
> +                    ret = -EIO;
> +                    goto ro_cleanup;
>                   }
>                   i++;
>   	    }
> @@ -614,6 +654,25 @@ int bdrv_commit(BlockDriverState *bs)
>        */
>       if (bs->backing_hd)
>           bdrv_flush(bs->backing_hd);
> +
> +ro_cleanup:
> +
> +    if (ro) {
> +        /* re-open as RO */
> +        bdrv_delete(bs->backing_hd);
> +        bs->backing_hd = NULL;
> +        bs_ro = bdrv_new("");
> +        ret = bdrv_open2(bs_ro, filename, open_flags&  ~BDRV_O_RDWR, NULL);
> +        if (ret<  0) {
> +            bdrv_delete(bs_ro);
> +            /* drive not functional anymore */
> +            bs->drv = NULL;
> +            return ret;
> +        }
> +        bs->backing_hd = bs_ro;
> +        bs->backing_hd->keep_read_only = 0;
> +    }
> +
>       return ret;
>   }
>
> diff --git a/block_int.h b/block_int.h
> index 930a5a4..50e1a0b 100644
> --- a/block_int.h
> +++ b/block_int.h
> @@ -130,6 +130,8 @@ struct BlockDriverState {
>       int64_t total_sectors; /* if we are reading a disk image, give its
>                                 size in sectors */
>       int read_only; /* if true, the media is read only */
> +    int keep_read_only; /* if true, the media was requested to stay read only */
> +    int open_flags; /* flags used to open the file, re-used for re-open */
>       int removable; /* if true, the media can be removed */
>       int locked;    /* if true, the media cannot temporarily be ejected */
>       int encrypted; /* if true, the media is encrypted */
>

Patch

diff --git a/block.c b/block.c
index af56ea7..31d1ba4 100644
--- a/block.c
+++ b/block.c
@@ -363,6 +363,7 @@  int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
     bs->is_temporary = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
+    bs->open_flags = flags;
     /* buffer_alignment defaulted to 512, drivers can change this value */
     bs->buffer_alignment = 512;
 
@@ -450,8 +451,6 @@  int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
     if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
         bs->enable_write_cache = 1;
 
-    bs->read_only = (flags & BDRV_O_RDWR) == 0;
-
     /*
      * Clear flags that are internal to the block layer before opening the
      * image.
@@ -472,6 +471,7 @@  int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
         goto free_and_fail;
     }
 
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
     if (drv->bdrv_getlength) {
         bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
     }
@@ -488,13 +488,22 @@  int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
                      filename, bs->backing_file);
         if (bs->backing_format[0] != '\0')
             back_drv = bdrv_find_format(bs->backing_format);
+
+        /* backing files always opened read-only */
+        open_flags &= ~BDRV_O_RDWR;
+        
         ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
                          back_drv);
-        bs->backing_hd->read_only =  (open_flags & BDRV_O_RDWR) == 0;
         if (ret < 0) {
             bdrv_close(bs);
             return ret;
         }
+        if (bs->is_temporary) {
+            bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+        } else {
+            /* base image inherits from "parent" */
+            bs->backing_hd->keep_read_only = bs->keep_read_only;
+        }
     }
 
     if (!bdrv_key_required(bs)) {
@@ -570,19 +579,48 @@  int bdrv_commit(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
     int64_t i, total_sectors;
-    int n, j;
-    int ret = 0;
+    int n, j, ro, open_flags;
+    int ret = 0, rw_ret = 0;
     unsigned char sector[512];
+    char filename[1024];
+    BlockDriverState *bs_rw, *bs_ro;
 
     if (!drv)
         return -ENOMEDIUM;
-
-    if (bs->read_only) {
-	return -EACCES;
+    
+    if (!bs->backing_hd) {
+        return -ENOTSUP;
     }
 
-    if (!bs->backing_hd) {
-	return -ENOTSUP;
+    if (bs->backing_hd->keep_read_only) {
+        return -EACCES;
+    }
+    
+    ro = bs->backing_hd->read_only;
+    strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+    open_flags =  bs->backing_hd->open_flags;
+
+    if (ro) {
+        /* re-open as RW */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_rw = bdrv_new("");
+        rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL);
+        if (rw_ret < 0) {
+            bdrv_delete(bs_rw);
+            /* try to re-open read-only */
+            bs_ro = bdrv_new("");
+            ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+            if (ret < 0) {
+                bdrv_delete(bs_ro);
+                /* drive not functional anymore */
+                bs->drv = NULL;
+                return ret;
+            }
+            bs->backing_hd = bs_ro;
+            return rw_ret;
+        }
+        bs->backing_hd = bs_rw;
     }
 
     total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
@@ -590,11 +628,13 @@  int bdrv_commit(BlockDriverState *bs)
         if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
             for(j = 0; j < n; j++) {
                 if (bdrv_read(bs, i, sector, 1) != 0) {
-                    return -EIO;
+                    ret = -EIO;
+                    goto ro_cleanup;
                 }
 
                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
-                    return -EIO;
+                    ret = -EIO;
+                    goto ro_cleanup;
                 }
                 i++;
 	    }
@@ -614,6 +654,25 @@  int bdrv_commit(BlockDriverState *bs)
      */
     if (bs->backing_hd)
         bdrv_flush(bs->backing_hd);
+
+ro_cleanup:
+
+    if (ro) {
+        /* re-open as RO */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_ro = bdrv_new("");
+        ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+        if (ret < 0) {
+            bdrv_delete(bs_ro);
+            /* drive not functional anymore */
+            bs->drv = NULL;
+            return ret;
+        }
+        bs->backing_hd = bs_ro;
+        bs->backing_hd->keep_read_only = 0;
+    }
+
     return ret;
 }
 
diff --git a/block_int.h b/block_int.h
index 930a5a4..50e1a0b 100644
--- a/block_int.h
+++ b/block_int.h
@@ -130,6 +130,8 @@  struct BlockDriverState {
     int64_t total_sectors; /* if we are reading a disk image, give its
                               size in sectors */
     int read_only; /* if true, the media is read only */
+    int keep_read_only; /* if true, the media was requested to stay read only */
+    int open_flags; /* flags used to open the file, re-used for re-open */
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */