nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 */ 00004 00014 #ifdef HAVE_CONFIG_H 00015 #include "config.h" 00016 #endif 00017 00018 #include "fsal.h" 00019 #include "fsal_internal.h" 00020 #include "fsal_common.h" 00021 00022 #include <string.h> 00023 #include <unistd.h> 00024 00025 00026 extern size_t i_snapshots; 00027 extern snapshot_t *p_snapshots; 00028 extern pthread_rwlock_t vfs_lock; 00029 pthread_t snapshot_thread; 00030 00031 __attribute(( unused )) static void *SnapshotThread(void *); 00032 00033 size_t stack_size = 0; 00034 00056 fsal_status_t ZFSFSAL_Init(fsal_parameter_t * init_info /* IN */ 00057 ) 00058 { 00059 static int is_initialized = 0; 00060 fsal_status_t status; 00061 zfsfs_specific_initinfo_t *spec_info = 00062 (zfsfs_specific_initinfo_t *) &init_info->fs_specific_info; 00063 00064 /* sanity check. */ 00065 if(is_initialized) 00066 { 00067 LogEvent(COMPONENT_FSAL, "INIT: blocking second call to FSAL_Init"); 00068 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_Init); 00069 } 00070 00071 if(!init_info) 00072 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_Init); 00073 00074 /* proceeds FSAL internal status initialization */ 00075 00076 status = fsal_internal_init_global(&(init_info->fsal_info), 00077 &(init_info->fs_common_info), 00078 &(init_info->fs_specific_info)); 00079 00080 if(FSAL_IS_ERROR(status)) 00081 Return(status.major, status.minor, INDEX_FSAL_Init); 00082 00083 /* Initilise the libzfswrap library */ 00084 p_zhd = libzfswrap_init(); 00085 if(!p_zhd) 00086 { 00087 LogCrit(COMPONENT_FSAL, "FSAL INIT: *** ERROR: Unable to initialize the libzfswrap library."); 00088 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_Init); 00089 } 00090 00091 /* Mount the zpool */ 00092 libzfswrap_vfs_t *p_vfs = libzfswrap_mount(spec_info->psz_zpool, "/tank", ""); 00093 if(!p_vfs) 00094 { 00095 libzfswrap_exit(p_zhd); 00096 LogCrit(COMPONENT_FSAL, "FSAL INIT: *** ERROR: Unable to mount the file system."); 00097 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_Init); 00098 } 00099 00100 /* List the snapshots of the given zpool and mount them */ 00101 const char *psz_error; 00102 char **ppsz_snapshots; 00103 i_snapshots = libzfswrap_zfs_get_list_snapshots(p_zhd, spec_info->psz_zpool, 00104 &ppsz_snapshots, &psz_error); 00105 00106 if(i_snapshots > 0) 00107 { 00108 LogDebug(COMPONENT_FSAL, "FSAL INIT: Found %zu snapshots.", i_snapshots); 00109 p_snapshots = calloc(i_snapshots + 1, sizeof(*p_snapshots)); 00110 p_snapshots[0].p_vfs = p_vfs; 00111 p_snapshots[0].index = 0; 00112 00113 int i,j; 00114 for(i = 0; i < i_snapshots; i++) 00115 { 00116 libzfswrap_vfs_t *p_snap_vfs = libzfswrap_mount(ppsz_snapshots[i], ppsz_snapshots[i], ""); 00117 if(!p_snap_vfs) 00118 { 00119 LogCrit(COMPONENT_FSAL, "FSAL INIT: *** ERROR: Unable to mount the snapshot %s", ppsz_snapshots[i]); 00120 for(j = i; j >= 0; j--) 00121 libzfswrap_umount(p_snapshots[j].p_vfs, 1); 00122 00123 libzfswrap_exit(p_zhd); 00124 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_Init); 00125 } 00126 00127 /* Change the name of the snapshot from zpool_name@snap_name to snap_name 00128 The '@' character is allways present, so no need to check it */ 00129 p_snapshots[i+1].psz_name = strdup(strchr(ppsz_snapshots[i], '@') + 1); 00130 p_snapshots[i+1].p_vfs = p_snap_vfs; 00131 p_snapshots[i+1].index = i + 1; 00132 00133 free(ppsz_snapshots[i]); 00134 } 00135 } 00136 else 00137 { 00138 LogDebug(COMPONENT_FSAL, "FSAL INIT: No snapshot found."); 00139 p_snapshots = calloc(1, sizeof(*p_snapshots)); 00140 p_snapshots[0].p_vfs = p_vfs; 00141 i_snapshots = 0; 00142 } 00143 pthread_rwlock_init(&vfs_lock, NULL); 00144 00145 /* Create a thread to handle snapshot creation */ 00146 if(spec_info->auto_snapshots) 00147 { 00148 LogDebug(COMPONENT_FSAL, "FSAL INIT: Creating the auto-snapshot thread"); 00149 zfsfs_specific_initinfo_t *fs_configuration = malloc(sizeof(*fs_configuration)); 00150 *fs_configuration = *spec_info; 00151 #if 0 00152 if(pthread_create(&snapshot_thread, NULL, SnapshotThread, fs_configuration)) 00153 { 00154 snapshot_thread = (pthread_t)NULL; 00155 ZFSFSAL_terminate(); 00156 Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_Init); 00157 } 00158 #endif 00159 } 00160 else 00161 { 00162 LogDebug(COMPONENT_FSAL, "FSAL INIT: No automatic snapshot creation"); 00163 snapshot_thread = (pthread_t)NULL; 00164 } 00165 00166 /* Everything went OK. */ 00167 is_initialized = 1; 00168 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_Init); 00169 00170 } 00171 00172 /* To be called before exiting */ 00173 fsal_status_t ZFSFSAL_terminate() 00174 { 00175 /* Join the snapshot thread if it does exist */ 00176 if(snapshot_thread) 00177 pthread_join(snapshot_thread, NULL); 00178 00179 /* Unmount every snapshots and free the memory */ 00180 int i; 00181 for(i = i_snapshots; i >= 0; i--) 00182 libzfswrap_umount(p_snapshots[i].p_vfs, 1); 00183 00184 for(i = 0; i < i_snapshots; i++) 00185 free(p_snapshots[i].psz_name); 00186 free(p_snapshots); 00187 00188 pthread_rwlock_destroy(&vfs_lock); 00189 00190 libzfswrap_exit(p_zhd); 00191 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00192 } 00193 00194 /* Take a snapshot */ 00195 __attribute(( unused )) static libzfswrap_vfs_t *TakeSnapshotAndMount(const char *psz_zpool, const char *psz_prefix, char **ppsz_name) 00196 { 00197 char psz_buffer[FSAL_MAX_NAME_LEN]; 00198 const char *psz_error; 00199 time_t time_now = time(NULL); 00200 struct tm *now = gmtime(&time_now); 00201 00202 asprintf(ppsz_name, "%s%d_%02d_%02d-%02d_%02d", 00203 psz_prefix, now->tm_year + 1900, now->tm_mon, 00204 now->tm_mday, now->tm_hour, now->tm_min); 00205 libzfswrap_zfs_snapshot(p_zhd, psz_zpool, *ppsz_name, &psz_error); 00206 00207 snprintf(psz_buffer, FSAL_MAX_NAME_LEN, "%s@%s%d_%02d_%02d-%02d_%02d", 00208 psz_zpool, psz_prefix, now->tm_year + 1900, now->tm_mon, 00209 now->tm_mday, now->tm_hour, now->tm_min); 00210 00211 LogDebug(COMPONENT_FSAL, "SNAPSHOTS: creating a new snapshot '%s'", psz_buffer); 00212 return libzfswrap_mount(psz_buffer, psz_buffer, ""); 00213 } 00214 00215 __attribute(( unused )) static void AddSnapshot(libzfswrap_vfs_t *p_vfs, char *psz_name) 00216 { 00217 i_snapshots++; 00218 if( ( p_snapshots = realloc(p_snapshots, (i_snapshots + 1) * sizeof(*p_snapshots)) ) == NULL ) 00219 { 00220 LogMajor(COMPONENT_FSAL, "SNAPSHOTS: recan't allocate memory... exiting"); 00221 free( p_snapshots ) ; 00222 exit( 1 ) ; 00223 return ; 00224 } 00225 00226 p_snapshots[i_snapshots].psz_name = psz_name; 00227 p_snapshots[i_snapshots].p_vfs = p_vfs; 00228 p_snapshots[i_snapshots].index = i_snapshots; 00229 } 00230 00231 __attribute(( unused )) static int CountSnapshot(const char *psz_prefix) 00232 { 00233 int i,count = 0; 00234 size_t len = strlen(psz_prefix); 00235 00236 for(i = 1; i < i_snapshots + 1; i++) 00237 if(!strncmp(p_snapshots[i].psz_name, psz_prefix, len)) 00238 count++; 00239 00240 return count; 00241 } 00242 00243 __attribute(( unused )) static void RemoveOldSnapshots(const char *psz_prefix, int number) 00244 { 00245 int i; 00246 char *psz_name; 00247 const char *psz_error; 00248 libzfswrap_vfs_t *p_vfs; 00249 size_t len = strlen(psz_prefix); 00250 00251 for(i = 0; i < number; i++) 00252 { 00253 int j, index = 1; 00254 for(j = 1; j < i_snapshots + 1; j++) 00255 { 00256 if(!strncmp(p_snapshots[j].psz_name, psz_prefix, len)) 00257 { 00258 if(strcmp(p_snapshots[j].psz_name, p_snapshots[index].psz_name) < 0) 00259 index = j; 00260 } 00261 } 00262 00263 /* We found a snapshot to remove */ 00264 psz_name = p_snapshots[index].psz_name; 00265 p_vfs = p_snapshots[index].p_vfs; 00266 00267 if(index != i_snapshots) 00268 memmove(&p_snapshots[index], &p_snapshots[index+1], (i_snapshots - index) * sizeof(*p_snapshots)); 00269 00270 i_snapshots--; 00271 if( ( p_snapshots = realloc(p_snapshots, (i_snapshots + 1) * sizeof(*p_snapshots)) ) == NULL ) 00272 { 00273 LogMajor(COMPONENT_FSAL, "SNAPSHOTS: recan't allocate memory... exiting"); 00274 free( p_snapshots ) ; 00275 exit( 1 ) ; 00276 return ; 00277 } 00278 00279 /* Really remove the snapshot */ 00280 LogDebug(COMPONENT_FSAL, "SNAPSHOTS: removing the snapshot '%s' (%d/%d)", psz_name, i + 1, number); 00281 libzfswrap_umount(p_vfs, 1); 00282 libzfswrap_zfs_snapshot_destroy(p_zhd, "tank", psz_name, &psz_error); 00283 } 00284 } 00285 00286 /* Thread that handle snapshots */ 00287 __attribute(( unused )) static void *SnapshotThread(void *data) 00288 { 00289 zfsfs_specific_initinfo_t *fs_info = (zfsfs_specific_initinfo_t*)data; 00290 00291 while(1) 00292 { 00293 /* Compute the time of the next snapshot */ 00294 time_t time_now = time(NULL); 00295 struct tm *now = gmtime(&time_now); 00296 unsigned int i_wait; 00297 char *psz_name; 00298 00299 if(now->tm_min >= fs_info->snap_hourly_time) 00300 i_wait = 60 - (now->tm_min - fs_info->snap_hourly_time); 00301 else 00302 i_wait = fs_info->snap_hourly_time - now->tm_min; 00303 00304 /* Sleep for the given time */ 00305 LogDebug(COMPONENT_FSAL, "SNAPSHOTS: next snapshot in %u minutes", i_wait); 00306 sleep(i_wait*60); 00307 00308 /* Create a snapshot */ 00309 libzfswrap_vfs_t *p_new = TakeSnapshotAndMount(fs_info->psz_zpool, 00310 fs_info->psz_snap_hourly_prefix, 00311 &psz_name); 00312 00313 /* Add the snapshot to the list of snapshots */ 00314 ZFSFSAL_VFS_WRLock(); 00315 AddSnapshot(p_new, psz_name); 00316 00317 /* Remove spurious snapshots */ 00318 int i_hourly_snap = CountSnapshot(fs_info->psz_snap_hourly_prefix); 00319 if(i_hourly_snap > fs_info->snap_hourly_number) 00320 RemoveOldSnapshots(fs_info->psz_snap_hourly_prefix, i_hourly_snap - fs_info->snap_hourly_number); 00321 00322 ZFSFSAL_VFS_Unlock(); 00323 } 00324 00325 return NULL; 00326 }