ShingledFS 2.0
SMR-AwareFUSE-basedFileSystem
|
00001 00012 #define FUSE_USE_VERSION 26 00013 00014 #define _XOPEN_SOURCE 500 00015 00016 #include <fuse.h> 00017 #include <fcntl.h> 00018 #include <stdio.h> 00019 #include <errno.h> 00020 #include <dirent.h> 00021 #include <limits.h> 00022 #include <string.h> 00023 #include <stdlib.h> 00024 #include <unistd.h> 00025 #include <sys/xattr.h> 00026 #include <sys/types.h> 00027 00028 #include <semaphore.h> 00029 #include <pthread.h> 00030 #include <signal.h> 00031 00032 00033 00034 /* ======================= */ 00035 /* -- Macro Definitions -- */ 00036 /* ======================= */ 00037 00038 #define GETATTR 0 00039 #define READLINK 1 00040 #define MKNOD 2 00041 #define MKDIR 3 00042 #define UNLINK 4 00043 #define RMDIR 5 00044 #define SYMLINK 6 00045 #define RENAME 7 00046 #define LINK 8 00047 #define CHMOD 9 00048 #define CHOWN 10 00049 #define TRUNCATE 11 00050 #define UTIME 12 00051 #define OPEN 13 00052 #define READ 14 00053 #define WRITE 15 00054 #define STATFS 16 00055 #define RELEASE 17 00056 #define FSYNC 18 00057 #define SETXATTR 19 00058 #define GETXATTR 20 00059 #define LISTXATTR 21 00060 #define REMOVEXATTR 22 00061 #define OPENDIR 23 00062 #define READDIR 24 00063 #define RELEASEDIR 25 00064 #define ACCESS 26 00065 00066 static int counters[27] = {0}; 00067 static FILE *file; 00068 00069 00070 00071 /* ====================== */ 00072 /* -- Static Variables -- */ 00073 /* ====================== */ 00074 00075 static char base[PATH_MAX]; 00076 static sem_t sem_profiler; 00077 00078 00079 00080 /* ============================== */ 00081 /* -- Function Implementations -- */ 00082 /* ============================== */ 00083 00084 00085 void *profiler() { 00086 while(1) { 00087 /* Wait for a profiling signal */ 00088 sem_wait(&sem_profiler); 00089 00090 00091 /* Open the file to write the application's profile */ 00092 file = fopen("/tmp/profile.out", "a+"); 00093 fprintf(file, "Profile:\n"); 00094 fprintf(file, "getattr()\t%d\n", counters[GETATTR]); 00095 fprintf(file, "readlink()\t%d\n", counters[READLINK]); 00096 fprintf(file, "mknod()\t%d\n", counters[MKNOD]); 00097 fprintf(file, "mkdir()\t%d\n", counters[MKDIR]); 00098 fprintf(file, "unlink()\t%d\n", counters[UNLINK]); 00099 fprintf(file, "rmdir()\t%d\n", counters[RMDIR]); 00100 fprintf(file, "symlink()\t%d\n", counters[SYMLINK]); 00101 fprintf(file, "rename()\t%d\n", counters[RENAME]); 00102 fprintf(file, "link()\t%d\n", counters[LINK]); 00103 fprintf(file, "chmod()\t%d\n", counters[CHMOD]); 00104 fprintf(file, "chown()\t%d\n", counters[CHOWN]); 00105 fprintf(file, "truncate()\t%d\n", counters[TRUNCATE]); 00106 fprintf(file, "utime()\t%d\n", counters[UTIME]); 00107 fprintf(file, "open()\t%d\n", counters[OPEN]); 00108 fprintf(file, "read()\t%d\n", counters[READ]); 00109 fprintf(file, "write()\t%d\n", counters[WRITE]); 00110 fprintf(file, "statfs()\t%d\n", counters[STATFS]); 00111 fprintf(file, "release()\t%d\n", counters[RELEASE]); 00112 fprintf(file, "fsync()\t%d\n", counters[FSYNC]); 00113 fprintf(file, "setxattr()\t%d\n", counters[SETXATTR]); 00114 fprintf(file, "getxattr()\t%d\n", counters[GETXATTR]); 00115 fprintf(file, "listxattr()\t%d\n", counters[LISTXATTR]); 00116 fprintf(file, "removexattr()\t%d\n", counters[REMOVEXATTR]); 00117 fprintf(file, "opendir()\t%d\n", counters[OPENDIR]); 00118 fprintf(file, "readdir()\t%d\n", counters[READDIR]); 00119 fprintf(file, "releasedir()\t%d\n", counters[RELEASEDIR]); 00120 fprintf(file, "access()\t%d\n", counters[ACCESS]); 00121 fprintf(file, "\n\n"); 00122 fclose(file); 00123 } 00124 00125 return NULL; 00126 } 00127 00128 00129 00130 void sig_handler(int sig) { 00131 /* Check the signal received */ 00132 if (sig == SIGUSR1) { 00133 fprintf(stderr, "Signaling...\n"); 00134 sem_post(&sem_profiler); 00135 signal(sig, sig_handler); 00136 } 00137 00138 } 00139 00140 00141 00146 void 00147 fullpath (const char *path, char *buf) 00148 { 00149 char *basedir = (char *) fuse_get_context ()->private_data; 00150 00151 strcpy (buf, basedir); 00152 strcat (buf, path); 00153 } 00154 00155 00156 /* The following functions describe FUSE operations. Each operation appends 00157 the path of the root filesystem to the given path in order to give the 00158 mirrored path. All quota checking takes place in fuse_write. */ 00159 00160 int 00161 fuse_getattr (const char *path, struct stat *buf) 00162 { 00163 char fpath[PATH_MAX]; 00164 int retval; 00165 fullpath (path, fpath); 00166 00167 counters[GETATTR]++; 00168 retval = lstat (fpath, buf) ? -errno : 0; 00169 return retval; 00170 } 00171 00172 int 00173 fuse_readlink (const char *path, char *target, size_t size) 00174 { 00175 char fpath[PATH_MAX]; 00176 int retval; 00177 fullpath (path, fpath); 00178 00179 counters[READLINK]++; 00180 retval = readlink (fpath, target, size); 00181 if (retval > 0) { 00182 if (retval == size) 00183 retval--; 00184 target[retval] = '\0'; 00185 retval = 0; 00186 } 00187 return retval; 00188 } 00189 00190 int 00191 fuse_mknod (const char *path, mode_t mode, dev_t dev) 00192 { 00193 char fpath[PATH_MAX]; 00194 int retval; 00195 fullpath (path, fpath); 00196 00197 counters[MKNOD]++; 00198 retval = mknod (fpath, mode | S_IRUSR | S_IWUSR, dev) ? -errno : 0; 00199 return retval; 00200 } 00201 00202 int 00203 fuse_mkdir (const char *path, mode_t mode) 00204 { 00205 char fpath[PATH_MAX]; 00206 int retval; 00207 fullpath (path, fpath); 00208 00209 counters[MKDIR]++; 00210 retval = mkdir (fpath, mode | S_IFDIR) ? -errno : 0; 00211 return retval; 00212 } 00213 00214 int 00215 fuse_unlink (const char *path) 00216 { 00217 char fpath[PATH_MAX]; 00218 int retval; 00219 fullpath (path, fpath); 00220 00221 counters[UNLINK]++; 00222 retval = unlink (fpath) ? -errno : 0; 00223 return retval; 00224 } 00225 00226 int 00227 fuse_rmdir (const char *path) 00228 { 00229 char fpath[PATH_MAX]; 00230 int retval; 00231 fullpath (path, fpath); 00232 00233 counters[RMDIR]++; 00234 retval = rmdir (fpath) ? -errno : 0; 00235 return retval; 00236 } 00237 00238 int 00239 fuse_symlink (const char *path, const char *link) 00240 { 00241 char flink[PATH_MAX]; 00242 int retval; 00243 fullpath (link, flink); 00244 00245 counters[SYMLINK]++; 00246 retval = symlink (path, flink) ? -errno : 0; 00247 return retval; 00248 } 00249 00250 int 00251 fuse_rename (const char *src, const char *dst) 00252 { 00253 char fsrc[PATH_MAX]; 00254 char fdst[PATH_MAX]; 00255 int retval; 00256 fullpath (src, fsrc); 00257 fullpath (dst, fdst); 00258 00259 counters[RENAME]++; 00260 retval = rename (fsrc, fdst) ? -errno : 0; 00261 return retval; 00262 } 00263 00264 int 00265 fuse_link (const char *src, const char *dst) 00266 { 00267 char fsrc[PATH_MAX]; 00268 char fdst[PATH_MAX]; 00269 int retval; 00270 fullpath (src, fsrc); 00271 fullpath (dst, fdst); 00272 00273 counters[LINK]++; 00274 retval = link (fsrc, fdst) ? -errno : 0; 00275 return retval; 00276 } 00277 00278 int 00279 fuse_chmod (const char *path, mode_t mode) 00280 { 00281 char fpath[PATH_MAX]; 00282 int retval; 00283 fullpath (path, fpath); 00284 00285 counters[CHMOD]++; 00286 retval = chmod (fpath, mode) ? -errno : 0; 00287 return retval; 00288 } 00289 00290 int 00291 fuse_chown (const char *path, uid_t uid, gid_t gid) 00292 { 00293 char fpath[PATH_MAX]; 00294 int retval; 00295 fullpath (path, fpath); 00296 00297 counters[CHOWN]++; 00298 retval = chown (fpath, uid, gid) ? -errno : 0; 00299 return retval; 00300 } 00301 00302 int 00303 fuse_truncate (const char *path, off_t off) 00304 { 00305 char fpath[PATH_MAX]; 00306 int retval; 00307 fullpath (path, fpath); 00308 00309 counters[TRUNCATE]++; 00310 retval = truncate (fpath, off) ? -errno : 0; 00311 return retval; 00312 } 00313 00314 int 00315 fuse_utime (const char *path, struct utimbuf *buf) 00316 { 00317 char fpath[PATH_MAX]; 00318 int retval; 00319 fullpath (path, fpath); 00320 00321 counters[UTIME]++; 00322 retval = utime (fpath, buf) ? -errno : 0; 00323 return retval; 00324 } 00325 00326 int 00327 fuse_open (const char *path, struct fuse_file_info *fi) 00328 { 00329 char fpath[PATH_MAX]; 00330 int retval; 00331 fullpath (path, fpath); 00332 00333 counters[OPEN]++; 00334 int fh = open (fpath, fi->flags); 00335 if (fh < 0) 00336 retval = -errno; 00337 else { 00338 fi->fh = fh; 00339 retval = 0; 00340 } 00341 00342 return retval; 00343 } 00344 00345 int 00346 fuse_read (const char *path, char *buf, size_t size, off_t off, 00347 struct fuse_file_info *fi) 00348 { 00349 int retval; 00350 00351 counters[READ]++; 00352 retval = pread (fi->fh, buf, size, off) < 0 ? -errno : size; 00353 return retval; 00354 } 00355 00356 int 00357 fuse_write (const char *path, const char *buf, size_t size, off_t off, 00358 struct fuse_file_info *fi) 00359 { 00360 int retval; 00361 00362 counters[WRITE]++; 00363 retval = pwrite (fi->fh, buf, size, off) < 0 ? -errno : size; 00364 return retval; 00365 } 00366 00367 int 00368 fuse_statfs (const char *path, struct statvfs *buf) 00369 { 00370 char fpath[PATH_MAX]; 00371 int retval; 00372 fullpath (path, fpath); 00373 00374 counters[STATFS]++; 00375 retval = statvfs (fpath, buf) ? -errno : 0; 00376 return retval; 00377 } 00378 00379 int 00380 fuse_release (const char *path, struct fuse_file_info *fi) 00381 { 00382 int retval; 00383 00384 counters[RELEASE]++; 00385 retval = close (fi->fh) ? -errno : 0; 00386 return retval; 00387 } 00388 00389 int 00390 fuse_fsync (const char *path, int datasync, struct fuse_file_info *fi) 00391 { 00392 int retval; 00393 00394 counters[FSYNC]++; 00395 if (datasync) 00396 retval = fdatasync (fi->fh) ? -errno : 0; 00397 else 00398 retval = fsync (fi->fh) ? -errno : 0; 00399 00400 return retval; 00401 } 00402 00403 int 00404 fuse_setxattr (const char *path, const char *name, const char *value, 00405 size_t size, int flags) 00406 { 00407 char fpath[PATH_MAX]; 00408 int retval; 00409 fullpath (path, fpath); 00410 00411 counters[SETXATTR]++; 00412 retval = lsetxattr (fpath, name, value, size, flags) ? -errno : 0; 00413 return retval; 00414 } 00415 00416 int 00417 fuse_getxattr (const char *path, const char *name, char *value, size_t size) 00418 { 00419 char fpath[PATH_MAX]; 00420 int retval; 00421 fullpath (path, fpath); 00422 00423 counters[GETXATTR]++; 00424 ssize_t s = lgetxattr (fpath, name, value, size); 00425 retval = s < 0 ? -errno : s; 00426 return retval; 00427 } 00428 00429 int 00430 fuse_listxattr (const char *path, char *list, size_t size) 00431 { 00432 char fpath[PATH_MAX]; 00433 int retval; 00434 fullpath (path, fpath); 00435 00436 counters[LISTXATTR]++; 00437 retval = llistxattr (fpath, list, size) < 0 ? -errno : 0; 00438 return retval; 00439 } 00440 00441 int 00442 fuse_removexattr (const char *path, const char *name) 00443 { 00444 char fpath[PATH_MAX]; 00445 int retval; 00446 fullpath (path, fpath); 00447 00448 counters[GETATTR]++; 00449 retval = lremovexattr (fpath, name) ? -errno : 0; 00450 return retval; 00451 } 00452 00453 int 00454 fuse_opendir (const char *path, struct fuse_file_info *fi) 00455 { 00456 char fpath[PATH_MAX]; 00457 int retval; 00458 fullpath (path, fpath); 00459 00460 counters[OPENDIR]++; 00461 DIR *dir = opendir (fpath); 00462 if (dir == NULL) 00463 retval = -errno; 00464 else { 00465 fi->fh = (uint64_t) dir; 00466 retval = 0; 00467 } 00468 00469 return retval; 00470 } 00471 00472 int 00473 fuse_readdir (const char *path, void *buf, fuse_fill_dir_t fill, off_t off, 00474 struct fuse_file_info *fi) 00475 { 00476 struct dirent *de = NULL; 00477 00478 counters[READDIR]++; 00479 while ((de = readdir ((DIR *) fi->fh)) != NULL) 00480 { 00481 struct stat st; 00482 memset (&st, 0, sizeof (struct stat)); 00483 st.st_ino = de->d_ino; 00484 st.st_mode = de->d_type << 12; 00485 00486 if (fill (buf, de->d_name, &st, 0)) 00487 break; 00488 } 00489 00490 return 0; 00491 } 00492 00493 int 00494 fuse_releasedir (const char *path, struct fuse_file_info *fi) 00495 { 00496 int retval; 00497 00498 counters[RELEASEDIR]++; 00499 retval = closedir ((DIR *) fi->fh) ? -errno : 0; 00500 return retval; 00501 } 00502 00503 int 00504 fuse_access (const char *path, int mode) 00505 { 00506 char fpath[PATH_MAX]; 00507 int retval; 00508 fullpath (path, fpath); 00509 00510 counters[ACCESS]++; 00511 retval = access (fpath, mode) ? -errno : 0; 00512 return retval; 00513 } 00514 00515 void * 00516 fuse_init (struct fuse_conn_info *conn) 00517 { 00518 pthread_t tid; 00519 int err; 00520 00521 /* Initialize the semaphore */ 00522 if ((err = sem_init(&sem_profiler, 0, 0)) != 0) 00523 exit(EXIT_FAILURE); 00524 00525 /* Install the signal handler */ 00526 signal(SIGUSR1, sig_handler); 00527 00528 /* Spawn a thread to profile the application */ 00529 if ((err = pthread_create(&tid, NULL, profiler, NULL)) != 0) 00530 exit(EXIT_FAILURE); 00531 00532 return (fuse_get_context())->private_data; 00533 } 00534 00535 00536 00537 struct fuse_operations fuse_ops = { 00538 .getattr = fuse_getattr, 00539 .readlink = fuse_readlink, 00540 .mknod = fuse_mknod, 00541 .mkdir = fuse_mkdir, 00542 .unlink = fuse_unlink, 00543 .rmdir = fuse_rmdir, 00544 .symlink = fuse_symlink, 00545 .rename = fuse_rename, 00546 .link = fuse_link, 00547 .chmod = fuse_chmod, 00548 .chown = fuse_chown, 00549 .truncate = fuse_truncate, 00550 .utime = fuse_utime, 00551 .open = fuse_open, 00552 .read = fuse_read, 00553 .write = fuse_write, 00554 .statfs = fuse_statfs, 00555 .release = fuse_release, 00556 .fsync = fuse_fsync, 00557 .setxattr = fuse_setxattr, 00558 .getxattr = fuse_getxattr, 00559 .listxattr = fuse_listxattr, 00560 .removexattr = fuse_removexattr, 00561 .opendir = fuse_opendir, 00562 .readdir = fuse_readdir, 00563 .releasedir = fuse_releasedir, 00564 .access = fuse_access, 00565 .init = fuse_init, 00566 }; 00567 00568 00569 00570 void 00571 usage () 00572 { 00573 printf ("transparency <basedir> <mountpoint>\n"); 00574 exit (0); 00575 } 00576 00577 00578 00579 int 00580 main (int argc, char *argv[]) 00581 { 00582 if (argc < 3) 00583 usage (); 00584 00585 if (realpath(argv[1], base) == NULL) 00586 printf("The base directory path %s is invalid!\n", argv[1]); 00587 00588 int i = 1; 00589 for (; i < argc; i++) 00590 argv[i] = argv[i + 1]; 00591 argc -= 1; 00592 00593 umask(0); 00594 int ret = fuse_main (argc, argv, &fuse_ops, base); 00595 if (ret < 0) 00596 printf("Error in FUSE main()\n"); 00597 else 00598 printf("Output will be found in /tmp/profile.out\n"); 00599 00600 return ret; 00601 }