/** Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open() call there will be exactly one release() call * with the same flags and file descriptor. It is possible to * have a file opened more than once, in which case only the last * release will mean, that no more reads/writes will happen on the * file. The return value of release is ignored. * * Changed in version 2.2 */ int cloudfs_release(const char *path, struct fuse_file_info *fi) { static int count; char new_name[MAX_NAME_LENGTH]; char symlink_name[MAX_NAME_LENGTH]; char buf[MAX_BUFFER_SIZE]; char fpath[PATH_MAX]; char symlink_path[PATH_MAX]; char file_to_link[PATH_MAX]; char new_hdd_path[PATH_MAX]; char attr_file_name[PATH_MAX]; char temp[PATH_MAX]; int retstat = 0; int fd; int temp_fd; int n; struct stat file_attributes; d_printf("\ncloudfs_release(path=\"%s\", fi=0x%08x)\n", path, fi); // log_fi(fi); //Read file attributes to get size of file fstat(fi->fh,&file_attributes); d_printf("Size of file is %d\n",file_attributes.st_size); //Open given file cloudfs_fullpath(fpath,path); if ((temp_fd = open(fpath,O_RDONLY)) < 0 ) cloudfs_error("Problem opening original file\n"); //Check if file is greater than threshold . //If yes then write the file to hdd with name large<static counter> //Delete the original file from ssd and create a symlink to new file //in hdd if (file_attributes.st_size > state_.threshold) { strcpy(new_hdd_path,path); get_new_name(new_hdd_path); //File's new name in HDD will have * instead of / strcpy(fpath, state_.hdd_path); strncat(fpath,new_hdd_path, PATH_MAX); strncpy(file_to_link,fpath,PATH_MAX); //Full name of new file is what //our symlink will point to fd = open(fpath,O_CREAT|O_RDWR,FILE_MODE); //Getting new fd of file if (fd < 0){ d_printf("Failed to open %s\n",fpath); retstat = cloudfs_error("cloudfs_create create error in HDD"); } while ( (n = read(temp_fd,buf,4096))> 0 ) { write(fd,buf,n); } //Close new file made close(fd); //Create hidden attribute file get_hidden_file_name(path,temp); strcpy(attr_file_name,temp); cloudfs_fullpath(fpath,path); append_to_end(fpath,attr_file_name); fd = open(fpath,O_CREAT|O_RDWR,FILE_MODE); //Getting fd of hidden file d_printf("Making hidden file %s\n",fpath); if (fd < 0){ d_printf("Failed to open %s\n",fpath); retstat = cloudfs_error("cloudfs_create create error of hidden attribute file"); } //Store attributes of migrated file in //extended attributes of hidden attribute file set_extended_attributes(fpath,&file_attributes); close(fd); //Close fd of hidden attribute file //Closing fd of original file and deleting //from SSD if ((retstat = close(temp_fd)) < 0) cloudfs_error("Error closing original file\n"); if ((retstat = close(fi->fh)) < 0) cloudfs_error("Error closing original file\n"); cloudfs_fullpath(fpath,path); d_printf("Trying to delete file %s\n",fpath); if( remove(fpath) < 0 ) cloudfs_error("Can't remove the file \n"); //Creating symlink cloudfs_fullpath(fpath,path); strcpy(symlink_name,fpath); fd = symlink(file_to_link,fpath); //Getting new fd of file if (fd < 0){ d_printf("Failed to make symlink %s\n",fpath); } return retstat; } // We need to close the file. Had we allocated any resources // (buffers etc) we'd need to free them here as well. else { if ((retstat = close(temp_fd)) < 0) cloudfs_error("Error closing original file\n"); if ((retstat = close(fi->fh)) < 0) cloudfs_error("Error closing original file\n"); return retstat; } }
static int get_insert_run_id( struct rldb_plugin_cnts *cdata, time_t t, int uid, int nsec) { struct rldb_file_cnts *cs = (struct rldb_file_cnts*) cdata; struct runlog_state *rls = cs->rl_state; int i, j; struct run_entry *runs = 0; ASSERT(rls->run_u <= rls->run_a); if (rls->run_u == rls->run_a) { int new_a = rls->run_a * 2; struct run_entry *new_r = 0; if (!new_a) new_a = 128; XCALLOC(new_r, new_a); for (i = 0; i < new_a; ++i) new_r[i].status = RUN_EMPTY; if (rls->run_u > 0) memcpy(new_r, rls->runs, rls->run_u * sizeof(rls->runs[0])); xfree(rls->runs); rls->runs = new_r; rls->run_a = new_a; } runs = rls->runs; /* * RUN_EMPTY compilicates things! :( */ if (!rls->run_u) return append_to_end(rls, t, nsec); j = rls->run_u - 1; while (j >= 0 && runs[j].status == RUN_EMPTY) j--; if (j < 0) return append_to_end(rls, t, nsec); if (t > runs[j].time) return append_to_end(rls, t, nsec); if (t == runs[j].time) { if (nsec < 0 && runs[j].nsec < NSEC_MAX) { nsec = runs[j].nsec + 1; return append_to_end(rls, t, nsec); } if (nsec > runs[j].nsec) return append_to_end(rls, t, nsec); if (nsec == runs[j].nsec && uid >= runs[j].user_id) return append_to_end(rls, t, nsec); } if (nsec < 0) { for (i = 0; i < rls->run_u; i++) { if (runs[i].status == RUN_EMPTY) continue; if (runs[i].time > t) break; if (runs[i].time < t) continue; // runs[i].time == t while (runs[i].status == RUN_EMPTY || runs[i].time == t) i++; j = i - 1; while (runs[j].status == RUN_EMPTY) j--; if (runs[j].nsec < NSEC_MAX) { nsec = runs[j].nsec + 1; break; } // DUMB :( nsec = random_u32() % (NSEC_MAX + 1); goto try_with_nsec; } ASSERT(i < rls->run_u); } else { try_with_nsec: for (i = 0; i < rls->run_u; i++) { if (runs[i].status == RUN_EMPTY) continue; if (runs[i].time > t) break; if (runs[i].time < t) continue; if (runs[i].nsec > nsec) break; if (runs[i].nsec < nsec) continue; if (runs[i].user_id > uid) break; } } /* So we going to insert a run at position i. * Check, that there is no "transient"-statused runs after this position. * This is very unlikely, because such runs appears when the run * is being compiled or run, and in this case its precise (nanosecond) * timestamp should be less, than the current run. However, if such * sutuation is detected, we fail because we cannot safely change * the run_id's when it is possible to receive compile or run response * packets. */ for (j = i; j < rls->run_u; j++) if (runs[j].status >= RUN_TRANSIENT_FIRST && runs[j].status <= RUN_TRANSIENT_LAST) break; if (j < rls->run_u) { err("append_record: cannot safely insert a run at position %d", i); err("append_record: the run %d is transient!", j); return -1; } memmove(&runs[i + 1], &runs[i], (rls->run_u - i) * sizeof(runs[0])); rls->run_u++; for (j = i + 1; j < rls->run_u; j++) runs[j].run_id = j; if (nsec < 0) nsec = 0; memset(&runs[i], 0, sizeof(runs[0])); runs[i].run_id = i; runs[i].status = RUN_EMPTY; runs[i].time = t; runs[i].nsec = nsec; if (sf_lseek(cs->run_fd, sizeof(rls->head) + i * sizeof(runs[0]), SEEK_SET, "run") == (off_t) -1) return -1; if (do_write(cs->run_fd, &runs[i], (rls->run_u - i) * sizeof(runs[0])) < 0) return -1; return i; }