]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Add support for expanding and contracting filesystems. Fix a few minor bugs
authorTheodore Ts'o <tytso@mit.edu>
Wed, 29 May 2002 03:16:10 +0000 (23:16 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 29 May 2002 03:16:10 +0000 (23:16 -0400)
since the last commit.

lib/evms/Makefile.in
lib/evms/fs_ext2.c
lib/evms/fsimext2.c
lib/evms/fsimext2.h

index 5ea517fa619b880dc749eeafcfff00a78e6b4ef0..cd3ced96300dcd4887669028237262ec8c314837 100644 (file)
@@ -5,7 +5,12 @@ top_builddir = ../..
 my_dir = lib/evms
 INSTALL = @INSTALL@
 
-XTRA_CFLAGS= -I@srcdir@
+MAJOR_VERSION  = 1
+MINOR_VERSION  = 0
+PATCH_LEVEL    = 0
+EXTRAVERSION   =
+
+XTRA_CFLAGS= -I@srcdir@ -DMAJOR_VERSION=$(MAJOR_VERSION) -DMINOR_VERSION=$(MINOR_VERSION) -DPATCH_LEVEL=$(PATCH_LEVEL)
 
 @MCONFIG@
 
@@ -17,8 +22,8 @@ SRCS= $(srcdir)/fs_ext2.c $(srcdir)/fsimext2.c
 LIBRARY= libext2fsim
 LIBDIR= evms
 
-ELF_VERSION = 1.0.0
-ELF_SO_VERSION = 1
+ELF_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_LEVEL)
+ELF_SO_VERSION = $(MAJOR_VERSION)
 ELF_IMAGE = libe2fsim
 ELF_MYDIR = evms
 ELF_INSTALL_DIR = $(root_libdir)
index baa954fa202b126e7a90894b6bb0aa6589542ec9..16c2a2f9c652d15f443750fbf352527a2ae48234 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <plugin.h>
+#include <sys/wait.h>
 #include "fsimext2.h"
 
 static plugin_record_t    *pMyPluginRecord = &ext2_plugrec;
@@ -50,12 +51,13 @@ static int fs_setup( engine_mode_t mode, engine_functions_t *engine_function_tab
      * this here in case we do at a later date....
      */
     rc = fsim_test_version();
+#if 0
     if ( rc ) {
         MESSAGE( "e2fsprogs must be version 1.XXX or later to function properly with this FSIM." );
         MESSAGE( "Please get the current version of e2fsprogs from http://e2fsprogs.sourceforge.net" );
         rc = ENOSYS;
     }
-     
+#endif
        LOGEXIT();
        return rc;
 }
@@ -257,10 +259,114 @@ static int fs_get_fs_limits( logical_volume_t * volume,
 static int fs_expand( logical_volume_t * volume,
                              sector_count_t   * new_size )
 {
-    /* unsupported at this time */
-       int  rc = ENOSYS;
+       struct ext2_super_block *sb;
+       int     rc = 0;
+       char   *argv[7];
+       pid_t   pidf;
+       int     status;
+       int     fds1[2];  /* pipe for stdin 0=read 1=write */
+       int     fds2[2];  /* pipe for stderr and stdout 0=-read,1=write */
+       int     bytes_read;
+       char    *buffer = NULL;
+       int     banner = 0;
 
        LOGENTRY();
+
+       /* get and validate current ext2/3 superblock */
+       sb = (struct ext2_super_block *) volume->private_data;  
+       rc = fsim_get_ext2_superblock( volume, sb );
+       if ((sb->s_lastcheck < sb->s_mtime) ||
+           (sb->s_state & EXT2_ERROR_FS) ||
+           ((sb->s_state & EXT2_VALID_FS) == 0)) {
+               MESSAGE("Running fsck before expanding volume");
+               rc = fsim_fsck(volume, NULL );
+               if (rc)
+                       goto errout;
+       }
+       
+       /* don't expand if mounted */
+       if (EngFncs->is_mounted(volume->name, NULL)) {
+               rc = EBUSY;
+               goto errout;
+       }
+
+       if (pipe(fds1)) {
+               rc = errno;
+               goto errout;
+       }
+       if (pipe(fds2)) {
+               rc = errno;
+               goto errout;
+       }
+       if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) {
+               rc = ENOMEM;
+               goto errout;
+       }
+
+       /* Fork and execute the correct program. */
+       switch (pidf = fork()) {
+
+       /* error */
+       case -1:
+               return EIO;
+
+               /* child */
+       case 0:  
+               argv[0] = "resize2fs";
+               SET_STRING_FIELD(argv[1], EVMS_GET_DEVNAME(volume));
+               argv[2] = NULL;
+
+               dup2(fds1[0],0);        /* fds1[0] replaces stdin */
+               dup2(fds2[1],1);        /* fds2[1] replaces stdout */
+               dup2(fds2[1],2);        /* fds2[1] replaces stderr */
+               close(fds2[0]);         /* don't need this here */
+               close(fds1[1]);         /* don't need this here */
+
+               rc = execvp( argv[0], argv );
+
+               /* using exit() can hang GUI, use _exit */
+               _exit(errno);
+
+               /* parent */
+       default:
+               /*
+                * WARNING: Do Not close read handle of stdin or
+                *  you will cause a SIGPIPE if you write after the 
+                * child process has gone away.
+                */
+/*             close(fds1[0]);  */
+               close(fds2[1]);
+
+               /* wait for child to complete */
+               while (!(pidf = waitpid( pidf, &status, WNOHANG ))) {
+                       bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+                       if (bytes_read > 0) {
+                               if (!banner)
+                                       MESSAGE("expand output:");
+                               banner = 1;
+                               MESSAGE("%s", buffer);
+                               memset(buffer,0,bytes_read); /* clear out message  */
+                       }
+                       usleep(10000); /* don't hog all the cpu */
+               }
+               /* do final read, just in case we missed some */
+               bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+               if (bytes_read > 0) {
+                       if (!banner)
+                               MESSAGE("expand output:");
+                       MESSAGE("%s",buffer);
+               }
+               if ( WIFEXITED(status) ) {
+                       /* get expand exit code */
+                       LOG("Expand completed with rc = %d \n",status);
+                       rc = WEXITSTATUS(status);
+               }
+       }
+       if (buffer) {
+               EngFncs->engine_free(buffer);
+       }
+       fs_get_fs_size(volume, new_size);
+errout:
        LOGEXITRC();
        return rc;
 }
@@ -294,10 +400,119 @@ static int fs_shrink( logical_volume_t * volume,
                              sector_count_t     requested_size,
                              sector_count_t   * new_size )
 {
-    /* unsupported at this time */
-       int  rc = ENOSYS;
+       int     rc = 0;
+       char   *argv[7];
+       pid_t   pidf;
+       int     status;
+       int     fds1[2];  /* pipe for stdin 0=read 1=write */
+       int     fds2[2];  /* pipe for stderr and stdout 0=-read,1=write */
+       int     bytes_read;
+       char    *buffer = NULL;
+       char    size_buf[128];
+       struct ext2_super_block *sb;
+       int     banner = 0;
 
        LOGENTRY();
+
+       /* don't shrink if mounted */
+       if (EVMS_IS_MOUNTED(volume)) {
+               LOGEXITRC();
+               return EBUSY;
+       }
+
+       /* get and validate current ext2/3 superblock */
+       sb = (struct ext2_super_block *) volume->private_data;  
+       rc = fsim_get_ext2_superblock( volume, sb );
+       requested_size = requested_size >> (1 + sb->s_log_block_size);
+       if ((sb->s_lastcheck < sb->s_mtime) ||
+           (sb->s_state & EXT2_ERROR_FS) ||
+           ((sb->s_state & EXT2_VALID_FS) == 0)) {
+               MESSAGE("Running fsck before shrinking volume");
+               rc = fsim_fsck(volume, NULL );
+               if (rc)
+                       goto errout;
+       }
+           
+       if (pipe(fds1)) {
+               rc = errno;
+               goto errout;
+       }
+       if (pipe(fds2)) {
+               rc = errno;
+               goto errout;
+       }
+       if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) {
+               rc = ENOMEM;
+               goto errout;
+       }
+
+       /* Fork and execute the correct program. */
+       switch (pidf = fork()) {
+
+       /* error */
+       case -1:
+               return EIO;
+
+               /* child */
+       case 0:  
+               argv[0] = "resize2fs";
+               SET_STRING_FIELD(argv[1], EVMS_GET_DEVNAME(volume));
+               sprintf(size_buf,"%lld", (sector_count_t)requested_size);
+               argv[2] = size_buf;
+               argv[3] = NULL;
+
+               dup2(fds1[0],0);        /* fds1[0] replaces stdin */
+               dup2(fds2[1],1);        /* fds2[1] replaces stdout */
+               dup2(fds2[1],2);        /* fds2[1] replaces stderr */
+               close(fds2[0]);         /*  don't need this here */
+               close(fds1[1]);         /*  don't need this here */
+
+               rc = execvp( argv[0], argv );
+
+               /* using exit() can hang GUI, use _exit */
+               _exit(errno);
+
+               /* parent */
+       default:
+               /*
+                * WARNING: Do Not close read handle of stdin or you
+                * will cause a SIGPIPE if you write after the child
+                * process has gone away.
+                */
+  /*           close(fds1[0]);  */
+               close(fds2[1]);
+               write(fds1[1], "Yes\n",4);  
+
+               /* wait for child to complete */
+               while (!(pidf = waitpid( pidf, &status, WNOHANG ))) {
+                       bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+                       if (bytes_read > 0) {
+                               if (!banner)
+                                       MESSAGE("Shrink output:");
+                               banner = 1;
+                               MESSAGE("%s", buffer);
+                               memset(buffer,0,bytes_read); /* clear out message  */
+                       }
+                       usleep(10000); /* don't hog all the cpu */
+               }
+               /* do final read, just in case we missed some */
+               bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+               if (bytes_read > 0) {
+                       if (!banner)
+                               MESSAGE("Shrink output:");
+                       MESSAGE("%s",buffer);
+               }
+               if ( WIFEXITED(status) ) {
+                       /* get shrink exit code */
+                       LOG("Shrink completed with rc = %d \n",status);
+                       rc = WEXITSTATUS(status);
+               }
+       }
+       if (buffer) {
+               EngFncs->engine_free(buffer);
+       }
+       fs_get_fs_size(volume, new_size);
+errout:
        LOGEXITRC();
        return rc;
 }
@@ -775,9 +990,7 @@ static int fs_set_volumes( task_context_t * context,
                                       task_effect_t  * effect )
 {
        int  rc = 0;
-    int64_t  log_size;
-    unsigned int  max_log_size;
-    logical_volume_t * vol;
+       logical_volume_t * vol;
 
        LOGENTRY();
 
@@ -960,7 +1173,7 @@ static int fs_get_plugin_info( char * descriptor_name, extended_info_array_t * *
        if (info) {
 
                if (descriptor_name == NULL) {
-                       *info = NULL;     // init to no info returned
+                       *info = NULL;     /* init to no info returned */
 
                        Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + (8*sizeof(extended_info_t))  );
                        if (Info) {
@@ -1027,7 +1240,7 @@ static int fs_get_plugin_info( char * descriptor_name, extended_info_array_t * *
                                iptr->collection_type    = EVMS_Collection_None;
                                memset( &iptr->group, 0, sizeof(group_info_t));
 
-#ifdef VERSION
+#if defined(PACKAGE) && defined(VERSION)
                                iptr = &Info->info[Info->count++];
                                SET_STRING_FIELD( iptr->name, "E2fsprogs Version" );
                                SET_STRING_FIELD( iptr->title, "E2fsprogs Version" );
@@ -1063,13 +1276,23 @@ static int fs_get_plugin_info( char * descriptor_name, extended_info_array_t * *
 static int fs_can_expand_by(logical_volume_t * volume, 
                             sector_count_t   * delta) 
 {
-    /* unsupported at this time */
-       int  rc = ENOSYS;
+       int  rc = 0;
 
        LOGENTRY();
+       if (EVMS_IS_MOUNTED(volume)) {
+               rc = EBUSY; /* If mounted, can't expand */
+               goto errout;
+       } 
+       fs_get_fs_limits( volume,       /* reset limits */
+                        &volume->min_fs_size,
+                        &volume->max_vol_size,
+                        &volume->max_fs_size);
+       if (volume->fs_size + *delta > volume->max_fs_size) {
+               *delta = volume->max_fs_size - volume->fs_size;
+       }
+errout:
        LOGEXITRC();
        return rc;
-
 }
 
 
@@ -1079,10 +1302,24 @@ static int fs_can_expand_by(logical_volume_t * volume,
 static int fs_can_shrink_by(logical_volume_t * volume, 
                             sector_count_t * delta) 
 {
-    /* unsupported at this time */
-       int  rc = ENOSYS;
+       int  rc = 0;
 
        LOGENTRY();
+       if (EVMS_IS_MOUNTED(volume)) {
+               rc = EBUSY; /* If mounted, can't shrink */
+               goto errout;
+       } 
+       fs_get_fs_limits( volume,       /* reset limits */
+                        &volume->min_fs_size,
+                        &volume->max_vol_size,
+                        &volume->max_fs_size);
+       if (volume->fs_size - *delta < volume->min_fs_size) {
+               *delta = volume->fs_size - volume->min_fs_size;
+       }
+       if (volume->min_fs_size >= volume->vol_size) {
+               rc = ENOSPC;
+       }
+errout:
        LOGEXITRC();
        return rc;
 }
index b826dd2c6b9cccf5057ccdae1f675cf961e4fac3..29f38bb3c93f22ceba34068c614869bf2fa2ac71 100644 (file)
@@ -36,7 +36,7 @@ int fsim_rw_diskblocks( int, int64_t, int32_t, void *, int );
 void set_mkfs_options( option_array_t *, char **, logical_volume_t *, char * );
 void set_fsck_options( option_array_t *, char **, logical_volume_t * );
 
-// Vector of plugin record ptrs that we export for the EVMS Engine. 
+/* Vector of plugin record ptrs that we export for the EVMS Engine.  */
 plugin_record_t *evms_plugin_records[] = {
        &ext2_plugrec,
        NULL
@@ -55,21 +55,23 @@ static plugin_record_t  * pMyPluginRecord = &ext2_plugrec;
  * Get the size limits for this volume.
  */
 int fsim_get_volume_limits( struct ext2_super_block * sb,
-                          sector_count_t    * min_size,
-                          sector_count_t    * max_volume_size,
-                          sector_count_t    * max_object_size)
+                         sector_count_t   * fs_min_size,
+                         sector_count_t   * fs_max_size,
+                         sector_count_t   * vol_max_size)
 {
        int rc = 0;
        sector_count_t fs_size;
+       int             blk_to_sect;
 
        /* 
         * Since ext2/3 does not yet support shrink or expand,
         * all values are actual file system size.
         */
-       fs_size = sb->s_blocks_count << (1 + sb->s_log_block_size);
-       *max_volume_size = fs_size;
-       *max_object_size = fs_size;
-       *min_size        = fs_size;
+       blk_to_sect = (1 + sb->s_log_block_size);
+       fs_size = sb->s_blocks_count << blk_to_sect;
+       *fs_min_size = (sb->s_blocks_count - sb->s_free_blocks_count) << blk_to_sect;
+       *fs_max_size = (sector_count_t) 1 << (32+blk_to_sect);
+       *vol_max_size = 0xffffffff;
 
        return rc;
 }
@@ -164,7 +166,8 @@ void set_mkfs_options( option_array_t * options,
                        logical_volume_t * volume, 
                        char * logsize )
 {
-    int i, opt_count = 2;
+    int i, bufsize, opt_count = 2;
+    char *buf;
 
     argv[0] = "mke2fs";
 
@@ -246,16 +249,20 @@ void set_mkfs_options( option_array_t * options,
     argv[opt_count++] = EVMS_GET_DEVNAME(volume);
     argv[opt_count] = NULL;
      
-    {
-           FILE        *f;
-
-           f = fopen("/var/tmp/evms-log", "a");
-           for ( i=0; argv[i]; i++) {
-                   fprintf(f, "'%s' ", argv[i]);
-           }
-           fprintf(f, "\n");
-           fclose(f);
+    bufsize = 0;
+    for (i=0; argv[i]; i++)
+           bufsize += strlen(argv[i]) + 5;
+    buf = malloc(bufsize+1);
+    if (!buf)
+           return;
+    buf[0] = 0;
+    for (i=0; argv[i]; i++) {
+           strcat(buf, argv[i]);
+           strcat(buf, " ");
     }
+    EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
+                            "mke2fs command: %s\n", buf);
+    free(buf);
     
     return;
 }
@@ -325,16 +332,21 @@ int fsim_fsck(logical_volume_t * volume, option_array_t * options )
                        if (bytes_read > 0) {
                                /* display e2fsck output */
                                if (!banner)
-                                       MESSAGE("e2fsck output: \n\n%s",buffer);
-                               else
-                                       banner = 1;
-                               memset(buffer,0,bytes_read); //clear out message  
+                                       MESSAGE("e2fsck output:");
+                               banner = 1;
+                               MESSAGE("%s",buffer);
+                               memset(buffer,0,bytes_read); /* clear out message  */
                        }
                        usleep(10000); /* don't hog all the cpu */
                }
 
-               /* wait for child to complete */
-               pidf = waitpid( pidf, &status, 0 );
+               /* do final read, just in case we missed some */
+               bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+               if (bytes_read > 0) {
+                       if (!banner)
+                               MESSAGE("e2fsck output:");
+                       MESSAGE("%s",buffer);
+               }
                if ( WIFEXITED(status) ) {
                        /* get e2fsck exit code */
                        rc = WEXITSTATUS(status);
@@ -363,12 +375,21 @@ int fsim_fsck(logical_volume_t * volume, option_array_t * options )
  */                        
 void set_fsck_options( option_array_t * options, char ** argv, logical_volume_t * volume )
 {
-    int i, opt_count = 1;
+    int i, bufsize, num_opts, opt_count = 1;
     int do_preen = 1;
+    char *buf;
 
     argv[0] = "e2fsck";
 
-    for ( i=0; i<options->count; i++) {
+    if (options) 
+           num_opts = options->count;
+    else {
+           /* No options, assume force (for resizing) */
+           argv[opt_count++] = "-f";
+           num_opts = 0;
+    }
+    
+    for ( i=0; i < num_opts; i++) {
 
         if ( options->option[i].is_number_based ) {
 
@@ -454,16 +475,20 @@ void set_fsck_options( option_array_t * options, char ** argv, logical_volume_t
     argv[opt_count++] = EVMS_GET_DEVNAME(volume);
     argv[opt_count]   = NULL;
 
-    {
-           FILE        *f;
-
-           f = fopen("/var/tmp/evms-log", "a");
-           for ( i=0; argv[i]; i++) {
-                   fprintf(f, "'%s' ", argv[i]);
-           }
-           fprintf(f, "\n");
-           fclose(f);
+    bufsize = 0;
+    for (i=0; argv[i]; i++)
+           bufsize += strlen(argv[i]) + 5;
+    buf = malloc(bufsize+1);
+    if (!buf)
+           return;
+    buf[0] = 0;
+    for (i=0; argv[i]; i++) {
+           strcat(buf, argv[i]);
+           strcat(buf, " ");
     }
+    EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
+                            "fsck command: %s\n", buf);
+    free(buf);
     
     return;
 }
index dd7d44bb21c9e2f009e582436590e577300746a9..d95aac78689b0ed9f8e083d86c4432aef6132ae7 100644 (file)
@@ -1,8 +1,3 @@
-/* Version number of the ext2 plugin */
-#define MAJOR_VERSION 1
-#define MINOR_VERSION 0
-#define PATCH_LEVEL 0
-
 /*
  *
  *   Copyright (c) International Business Machines  Corp., 2000
 extern plugin_record_t ext2_plugrec;
 engine_functions_t *EngFncs;
                  
-// file system type ... used by the SetPluginID macro
+/*  file system type ... used by the SetPluginID macro */
 #define FS_TYPE_EXT2     7
                  
-// logging macros 
+/*  logging macros  */
 #define LOGENTRY()                  EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s:  Enter.\n", __FUNCTION__)
 #define LOGEXIT()                   EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s:  Exit.\n", __FUNCTION__ )
 #define LOGEXITRC()                 EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s:  Exit.  RC= %d.\n", __FUNCTION__, rc)
@@ -64,7 +59,7 @@ engine_functions_t *EngFncs;
 #define LOG_DEBUG(msg, args...)                EngFncs->write_log_entry(DEBUG, pMyPluginRecord, __FUNCTION__ ": " msg, ## args)
 #define LOG_EXTRA(msg, args...)                EngFncs->write_log_entry(EXTRA, pMyPluginRecord, __FUNCTION__ ": " msg, ## args)
 
-// useful macro for option code
+/*  useful macro for option code */
 #define SET_STRING_FIELD(a,b)\
 a = EngFncs->engine_alloc( strlen(b)+1 );\
 if (a ) {\