| 1 | #include <stdio.h> |
|---|
| 2 | #include <usrint.h> |
|---|
| 3 | #include "ucached.h" |
|---|
| 4 | |
|---|
| 5 | /* FIFO */ |
|---|
| 6 | static int readfd = 0; /* Command File Descriptor */ |
|---|
| 7 | static int writefd = 0; /* Response File Descriptor */ |
|---|
| 8 | static char buffer[BUFF_SIZE]; /* For FIFO reads and writes */ |
|---|
| 9 | char buff[LOG_LEN]; |
|---|
| 10 | |
|---|
| 11 | /* Time Structures For Log |
|---|
| 12 | static time_t rawtime; |
|---|
| 13 | static struct tm * timeinfo; |
|---|
| 14 | */ |
|---|
| 15 | |
|---|
| 16 | /* Booleans */ |
|---|
| 17 | /* 1 if ucache is available for use */ |
|---|
| 18 | static unsigned char ucache_avail = 0; |
|---|
| 19 | /* Set this to one if the ucache doesn't get created, and the |
|---|
| 20 | * create_ucache_shmem function should be run again. |
|---|
| 21 | */ |
|---|
| 22 | //static unsigned char tryAgain = 0; |
|---|
| 23 | |
|---|
| 24 | /* Use this global to determine if the atexit registered function (clean_up) |
|---|
| 25 | * needs to run. A child process is created to create shmem. This facilitates |
|---|
| 26 | * destruction later on, since segments hang around until their creator exits. |
|---|
| 27 | */ |
|---|
| 28 | pid_t pid = -1; |
|---|
| 29 | |
|---|
| 30 | /* Hung Lock Detection */ |
|---|
| 31 | time_t locked_time[BLOCKS_IN_CACHE+1]; |
|---|
| 32 | |
|---|
| 33 | /* Forward Function Declarations */ |
|---|
| 34 | static int run_as_child(char c); /* Run as child of ucached */ |
|---|
| 35 | static int execute_cmd(char command); |
|---|
| 36 | static int create_ucache_shmem(void); |
|---|
| 37 | static int destroy_ucache_shmem(char dest_locks, char dest_ucache); |
|---|
| 38 | static void clean_up(void); |
|---|
| 39 | static int ucached_lockchk(void); |
|---|
| 40 | |
|---|
| 41 | void check_rc(int rc) |
|---|
| 42 | { |
|---|
| 43 | memset(buffer, 0, BUFF_SIZE); |
|---|
| 44 | if(rc >= 0) |
|---|
| 45 | { |
|---|
| 46 | strcpy(buffer, "SUCCESS"); |
|---|
| 47 | } |
|---|
| 48 | else |
|---|
| 49 | { |
|---|
| 50 | strcpy(buffer, "FAILURE: check log:" UCACHED_LOG_FILE); |
|---|
| 51 | } |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | /** Function to be run upon successful termination from an exit call */ |
|---|
| 55 | static void clean_up(void) |
|---|
| 56 | { |
|---|
| 57 | int rc = 0; |
|---|
| 58 | /* Only the parent process should execute these lines. |
|---|
| 59 | * Must check the pid since the atexit function registered |
|---|
| 60 | * clean_up. This registration is passed on to any child |
|---|
| 61 | * processes forked off of the parent. We don't want to execute |
|---|
| 62 | * these lines when any of the children exit. Run only when parent. |
|---|
| 63 | */ |
|---|
| 64 | if(pid !=0) |
|---|
| 65 | { |
|---|
| 66 | if(DEST_AT_EXIT) |
|---|
| 67 | { |
|---|
| 68 | rc = destroy_ucache_shmem(1, 1); |
|---|
| 69 | } |
|---|
| 70 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 71 | "INFO: ucached exiting...PID=%d\n", pid); |
|---|
| 72 | rc = unlink(FIFO1); |
|---|
| 73 | rc = unlink(FIFO2); |
|---|
| 74 | } |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | /** Checks ucache lock shmem region for hung locks. |
|---|
| 78 | * Returns 0 when no hung locks are detected. |
|---|
| 79 | * Returns 1 when 1 or more hung locks are detected and all are gracefully |
|---|
| 80 | * handled. |
|---|
| 81 | * Returns -1 when 1 or more hung locks are detected and couldn't |
|---|
| 82 | * be handled properly. (error) |
|---|
| 83 | */ |
|---|
| 84 | static int ucached_lockchk(void) |
|---|
| 85 | { |
|---|
| 86 | int rc = 0; |
|---|
| 87 | int i; |
|---|
| 88 | for(i = 0; i < (BLOCKS_IN_CACHE + 1); i++) |
|---|
| 89 | { |
|---|
| 90 | ucache_lock_t * currlock = get_lock((uint16_t)i); |
|---|
| 91 | if(lock_trylock(currlock) == 0) |
|---|
| 92 | { |
|---|
| 93 | /* Lock wasn't held, so set the timer to zero for this lock */ |
|---|
| 94 | locked_time[i] = 0; |
|---|
| 95 | } |
|---|
| 96 | else |
|---|
| 97 | { |
|---|
| 98 | /* Lock was held, so calculate if lock timeout has occured */ |
|---|
| 99 | /* First check to see if this lock's timer has been set at all */ |
|---|
| 100 | if(!locked_time[i]) |
|---|
| 101 | { |
|---|
| 102 | /* Timer for this lock isn't currently set */ |
|---|
| 103 | time(&locked_time[i]); |
|---|
| 104 | continue; |
|---|
| 105 | } |
|---|
| 106 | else |
|---|
| 107 | { |
|---|
| 108 | /* Timer was previously set meaning the block had been locked*/ |
|---|
| 109 | double time_diff = difftime(time((time_t *)NULL), locked_time[i]); |
|---|
| 110 | if((int)time_diff >= BLOCK_LOCK_TIMEOUT) |
|---|
| 111 | { |
|---|
| 112 | /* |
|---|
| 113 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 114 | "WARNING: HUNG LOCK DETECTED @ block index = %d\n", i); |
|---|
| 115 | TODO: what to do with hung locks? |
|---|
| 116 | rc = pick_lock(ucache_lock_t * currlock); |
|---|
| 117 | if(rc == 1) |
|---|
| 118 | { |
|---|
| 119 | locked_time[i] = (time_t)0; |
|---|
| 120 | } |
|---|
| 121 | */ |
|---|
| 122 | } |
|---|
| 123 | } |
|---|
| 124 | } |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | return rc; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | /** Runs the command in a child process */ |
|---|
| 132 | static int run_as_child(char c) |
|---|
| 133 | { |
|---|
| 134 | pid = fork(); |
|---|
| 135 | int rc = 0; |
|---|
| 136 | /* Fork Error? */ |
|---|
| 137 | if(pid < 0) |
|---|
| 138 | { |
|---|
| 139 | exit(EXIT_FAILURE); |
|---|
| 140 | } |
|---|
| 141 | /* Child Process */ |
|---|
| 142 | else if(pid == 0) |
|---|
| 143 | { |
|---|
| 144 | rc = execute_cmd(c); |
|---|
| 145 | if(rc < 0) |
|---|
| 146 | { |
|---|
| 147 | exit(EXIT_FAILURE); |
|---|
| 148 | } |
|---|
| 149 | exit(EXIT_SUCCESS); |
|---|
| 150 | } |
|---|
| 151 | /* Parent Process */ |
|---|
| 152 | else |
|---|
| 153 | { |
|---|
| 154 | wait(&rc); |
|---|
| 155 | if(WIFEXITED(rc)) |
|---|
| 156 | { |
|---|
| 157 | if(WEXITSTATUS(rc) != 0) |
|---|
| 158 | { |
|---|
| 159 | return -1; |
|---|
| 160 | } |
|---|
| 161 | } |
|---|
| 162 | } |
|---|
| 163 | return rc; |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | |
|---|
| 167 | static int execute_cmd(char cmd) |
|---|
| 168 | { |
|---|
| 169 | int rc = 0; |
|---|
| 170 | switch(cmd) |
|---|
| 171 | { |
|---|
| 172 | /* Create the shared memory required by the ucache */ |
|---|
| 173 | case 'c': |
|---|
| 174 | rc = create_ucache_shmem(); |
|---|
| 175 | break; |
|---|
| 176 | /* Destroy the shared memory required by the ucache */ |
|---|
| 177 | case 'd': |
|---|
| 178 | rc = destroy_ucache_shmem(1, 1); |
|---|
| 179 | break; |
|---|
| 180 | case 'i': |
|---|
| 181 | rc = ucache_info(stdout, "sav"); |
|---|
| 182 | break; |
|---|
| 183 | /* Close Daemon */ |
|---|
| 184 | case 'x': |
|---|
| 185 | writefd = open(FIFO2, O_WRONLY); |
|---|
| 186 | rc = write(writefd, "SUCCESS\tExiting ucached", BUFF_SIZE); |
|---|
| 187 | while(rc <= 0) |
|---|
| 188 | { |
|---|
| 189 | rc = write(writefd, "SUCCESS\tExiting ucached", BUFF_SIZE); |
|---|
| 190 | } |
|---|
| 191 | close(writefd); |
|---|
| 192 | exit(EXIT_SUCCESS); |
|---|
| 193 | break; |
|---|
| 194 | default: |
|---|
| 195 | strcpy(buffer, "FAILURE\tInvalid command character"); |
|---|
| 196 | break; |
|---|
| 197 | } |
|---|
| 198 | return rc; |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | /* Returns -1 on failure, 1 on success */ |
|---|
| 202 | static int create_ucache_shmem(void) |
|---|
| 203 | { |
|---|
| 204 | int rc = 0; |
|---|
| 205 | |
|---|
| 206 | int old_locks_present = 0; |
|---|
| 207 | |
|---|
| 208 | /* attempt setup of shmem region for locks (inlcude SYSV later? */ |
|---|
| 209 | int id = SHM_ID1; |
|---|
| 210 | key_t key = ftok(KEY_FILE, id); |
|---|
| 211 | size_t size = LOCKS_SIZE; |
|---|
| 212 | int shmflg = SVSHM_MODE; |
|---|
| 213 | int lock_shmid = shmget(key, size, shmflg); |
|---|
| 214 | |
|---|
| 215 | if(lock_shmid == -1) |
|---|
| 216 | { |
|---|
| 217 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 218 | "INFO: shmget on lock_shmid returned -1 on first try\n"); |
|---|
| 219 | |
|---|
| 220 | /* Shared memory segment used for locks was not previosly created, |
|---|
| 221 | * so create it. |
|---|
| 222 | */ |
|---|
| 223 | shmflg = shmflg | IPC_CREAT | IPC_EXCL; |
|---|
| 224 | lock_shmid = shmget(key, size, shmflg); |
|---|
| 225 | if(lock_shmid == -1) |
|---|
| 226 | { |
|---|
| 227 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 228 | "ERROR: shmget (IPC_CREATE, IPC_EXCL)" |
|---|
| 229 | " on lock_shmid returned -1\n"); |
|---|
| 230 | /* Couldn't create the required segment */ |
|---|
| 231 | return -1; |
|---|
| 232 | } |
|---|
| 233 | else |
|---|
| 234 | { |
|---|
| 235 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 236 | "INFO: shmget (using IPC_CREATE, IPC_EXCL)" |
|---|
| 237 | " on lock_shmid returned shmid = %d\n", lock_shmid); |
|---|
| 238 | |
|---|
| 239 | /* Attach to shmem and initialize all the locks */ |
|---|
| 240 | shmflg = 0; |
|---|
| 241 | /* ucache_locks is defined in src/client/usrint/ucache.h */ |
|---|
| 242 | ucache_locks = shmat(lock_shmid, NULL, shmflg); |
|---|
| 243 | if (!ucache_locks) |
|---|
| 244 | { |
|---|
| 245 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 246 | "ERROR: shmat on lock_shmid returned NULL"); |
|---|
| 247 | return -1; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | int i; |
|---|
| 251 | /* Initialize Block Level Locks */ |
|---|
| 252 | for(i = 0; i < (BLOCKS_IN_CACHE + 1); i++) |
|---|
| 253 | { |
|---|
| 254 | rc = lock_init(get_lock(i)); |
|---|
| 255 | if (rc == -1) |
|---|
| 256 | { |
|---|
| 257 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 258 | "ERROR: lock_init returned -1 @ lock index = %d\n", i); |
|---|
| 259 | rc = -1; |
|---|
| 260 | } |
|---|
| 261 | } |
|---|
| 262 | } |
|---|
| 263 | } |
|---|
| 264 | else |
|---|
| 265 | { |
|---|
| 266 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 267 | "INFO: first shmget on lock_shmid found segment" |
|---|
| 268 | ": shmid = %d\n", lock_shmid); |
|---|
| 269 | old_locks_present = 1; |
|---|
| 270 | /* Shmem for locks was already created, so just attach to it */ |
|---|
| 271 | shmflg = 0; |
|---|
| 272 | ucache_locks = shmat(lock_shmid, NULL, shmflg); |
|---|
| 273 | if (!ucache_locks) |
|---|
| 274 | { |
|---|
| 275 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 276 | "ERROR: shmat on lock_shmid returned NULL\n"); |
|---|
| 277 | return -1; |
|---|
| 278 | } |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | /* At this point all the locks should be aquired and initialized. |
|---|
| 282 | * They could also be locked or unlocked */ |
|---|
| 283 | |
|---|
| 284 | /* Set the global lock point to the address of the last lock in the locks |
|---|
| 285 | * shmem segment. Then lock it. |
|---|
| 286 | */ |
|---|
| 287 | ucache_lock = get_lock(BLOCKS_IN_CACHE); |
|---|
| 288 | lock_lock(ucache_lock); |
|---|
| 289 | |
|---|
| 290 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 291 | "INFO: lock segment successfully retrieved and global lock locked.\n"); |
|---|
| 292 | |
|---|
| 293 | /* Try to get/create the shmem required for the ucache */ |
|---|
| 294 | id = SHM_ID2; |
|---|
| 295 | key = ftok(KEY_FILE, id); |
|---|
| 296 | size = CACHE_SIZE; |
|---|
| 297 | shmflg = SVSHM_MODE; |
|---|
| 298 | int ucache_shmid = shmget(key, size, shmflg); |
|---|
| 299 | |
|---|
| 300 | if(ucache_shmid == -1) |
|---|
| 301 | { |
|---|
| 302 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 303 | "INFO: shmget on ucache_shmid returned -1 first try\n"); |
|---|
| 304 | |
|---|
| 305 | /* Remember if there was an old lock region detected */ |
|---|
| 306 | if(old_locks_present) |
|---|
| 307 | { |
|---|
| 308 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 309 | "INFO: old locks discovered, attempting destruction of old" |
|---|
| 310 | " locks and starting\n"); |
|---|
| 311 | |
|---|
| 312 | /* Destroy old lock region and start function over */ |
|---|
| 313 | rc = shmctl(lock_shmid, IPC_RMID, (struct shmid_ds *) NULL); |
|---|
| 314 | |
|---|
| 315 | /* Let this child process exit, since exiting is required to get |
|---|
| 316 | * the shmem segment to be completely removed. Try to create the |
|---|
| 317 | * shmem again later in another child process. |
|---|
| 318 | */ |
|---|
| 319 | return -1; |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | /* Shared memory segmet used for ucache was not previosly created, |
|---|
| 323 | * so create it. |
|---|
| 324 | */ |
|---|
| 325 | shmflg = shmflg | IPC_CREAT | IPC_EXCL; |
|---|
| 326 | ucache_shmid = shmget(key, size, shmflg); |
|---|
| 327 | if(ucache_shmid == -1) |
|---|
| 328 | { |
|---|
| 329 | /* Couldn't create the required segment */ |
|---|
| 330 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 331 | "ERROR: shmget (using IPC_CREATE, IPC_EXCL)" |
|---|
| 332 | " on ucache_shmid returned -1\n"); |
|---|
| 333 | |
|---|
| 334 | rc = -1; |
|---|
| 335 | goto errout; |
|---|
| 336 | } |
|---|
| 337 | else |
|---|
| 338 | { |
|---|
| 339 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 340 | "INFO: shmget (using IPC_CREATE, IPC_EXCL)" |
|---|
| 341 | " on ucache_shmid returned shmid = %d\n", ucache_shmid); |
|---|
| 342 | |
|---|
| 343 | /* Attach to the ucache shmem region */ |
|---|
| 344 | shmflg = 0; |
|---|
| 345 | /* ucache is defined in src/client/usrint/ucache.h */ |
|---|
| 346 | ucache = shmat(ucache_shmid, NULL, shmflg); |
|---|
| 347 | if (!ucache) |
|---|
| 348 | { |
|---|
| 349 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 350 | "ERROR: shmat on ucache_shmid returned NULL\n"); |
|---|
| 351 | rc = -1; |
|---|
| 352 | goto errout; |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | /* Initialize the file table */ |
|---|
| 356 | rc = ucache_init_file_table(0); |
|---|
| 357 | if(rc != 0) |
|---|
| 358 | { |
|---|
| 359 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 360 | "ERROR: file table initialization failed\n"); |
|---|
| 361 | /* Couldn't Initialize File Table */ |
|---|
| 362 | rc = -1; |
|---|
| 363 | goto errout; |
|---|
| 364 | } |
|---|
| 365 | } |
|---|
| 366 | } |
|---|
| 367 | else |
|---|
| 368 | { |
|---|
| 369 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 370 | "INFO: first shmget on ucache_shmid found segment" |
|---|
| 371 | ": shmid = %d\n", ucache_shmid); |
|---|
| 372 | |
|---|
| 373 | /* Previously created ucache segment present. Need more info. */ |
|---|
| 374 | /* See if marked for deletion, but has users attached still */ |
|---|
| 375 | struct shmid_ds buf; |
|---|
| 376 | int cmd = IPC_STAT; |
|---|
| 377 | rc = shmctl(ucache_shmid, cmd, &buf); |
|---|
| 378 | if(rc == -1) |
|---|
| 379 | { |
|---|
| 380 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 381 | "ERROR: shmctl failed to IPC_STAT ucache_shmid\n"); |
|---|
| 382 | goto errout; |
|---|
| 383 | } |
|---|
| 384 | |
|---|
| 385 | /* Determine the count of processes attached to this shm segment */ |
|---|
| 386 | char hasAttached = (buf.shm_nattch > 0); |
|---|
| 387 | |
|---|
| 388 | /* Determine if the ucache shmem segment is marked for destruction*/ |
|---|
| 389 | uint16_t currentMode = buf.shm_perm.mode; |
|---|
| 390 | char markedForDest = ((currentMode & SHM_DEST) == SHM_DEST); |
|---|
| 391 | |
|---|
| 392 | if(markedForDest && hasAttached) |
|---|
| 393 | { |
|---|
| 394 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 395 | "INFO: detected previous ucache shmem segment" |
|---|
| 396 | " marked for destruction that still has" |
|---|
| 397 | " one or more processes attached to it.\n"); |
|---|
| 398 | |
|---|
| 399 | shmflg = shmflg | IPC_CREAT; /* Note: CREAT w/o EXCL */ |
|---|
| 400 | ucache_shmid = shmget(key, size, shmflg); |
|---|
| 401 | if(ucache_shmid == -1) |
|---|
| 402 | { |
|---|
| 403 | /* Couldn't create the required segment */ |
|---|
| 404 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 405 | "ERROR: shmget (using IPC_CREAT && !EXCL)" |
|---|
| 406 | " on ucache_shmid returned -1\n"); |
|---|
| 407 | rc = -1; |
|---|
| 408 | goto errout; |
|---|
| 409 | } |
|---|
| 410 | /* Attach to the ucache shmem region */ |
|---|
| 411 | shmflg = 0; |
|---|
| 412 | /* ucache is defined in src/client/usrint/ucache.h */ |
|---|
| 413 | ucache = shmat(ucache_shmid, NULL, shmflg); |
|---|
| 414 | if (!ucache) |
|---|
| 415 | { |
|---|
| 416 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 417 | "ERROR: shmat on ucache_shmid returned NULL\n"); |
|---|
| 418 | rc = -1; |
|---|
| 419 | goto errout; |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | /* Initialize the ftbl, and force the creation of it |
|---|
| 423 | * since the init boolean is set to 1. |
|---|
| 424 | */ |
|---|
| 425 | rc = ucache_init_file_table(1); |
|---|
| 426 | if(rc != 0) |
|---|
| 427 | { |
|---|
| 428 | /* Couldn't Initialize File Table */ |
|---|
| 429 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 430 | "ERROR: file table initialization failed\n"); |
|---|
| 431 | rc = -1; |
|---|
| 432 | goto errout; |
|---|
| 433 | } |
|---|
| 434 | } |
|---|
| 435 | else |
|---|
| 436 | { |
|---|
| 437 | /* Asume we will keep using the previously allocated segment */ |
|---|
| 438 | /* Attach to the ucache shmem region */ |
|---|
| 439 | shmflg = 0; |
|---|
| 440 | /* ucache is defined in src/client/usrint/ucache.h */ |
|---|
| 441 | ucache = shmat(ucache_shmid, NULL, shmflg); |
|---|
| 442 | if (!ucache) |
|---|
| 443 | { |
|---|
| 444 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 445 | "ERROR: shmat on ucache_shmid returned NULL\n"); |
|---|
| 446 | rc = -1; |
|---|
| 447 | goto errout; |
|---|
| 448 | } |
|---|
| 449 | } |
|---|
| 450 | } |
|---|
| 451 | |
|---|
| 452 | lock_unlock(ucache_lock); |
|---|
| 453 | return 1; |
|---|
| 454 | |
|---|
| 455 | errout: |
|---|
| 456 | lock_unlock(ucache_lock); |
|---|
| 457 | return rc; |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | static int destroy_ucache_shmem(char dest_locks, char dest_ucache) |
|---|
| 461 | { |
|---|
| 462 | int rc = 0; |
|---|
| 463 | /* Aquire the main lock then attempt to destroy the ucache shmem segment */ |
|---|
| 464 | if(ucache_lock) |
|---|
| 465 | { |
|---|
| 466 | lock_lock(ucache_lock); |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | if(dest_ucache) |
|---|
| 470 | { |
|---|
| 471 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 472 | "INFO: destroying ucache shmem\n"); |
|---|
| 473 | |
|---|
| 474 | /* Destroy shmem segment containing ucache */ |
|---|
| 475 | int id = SHM_ID2; |
|---|
| 476 | key_t key = ftok(KEY_FILE, id); |
|---|
| 477 | int shmflg = SVSHM_MODE; |
|---|
| 478 | int ucache_shmid = shmget(key, 0, shmflg); |
|---|
| 479 | if(ucache_shmid == -1) |
|---|
| 480 | { |
|---|
| 481 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 482 | "ERROR: shmget on ucache_shmid returned -1\n"); |
|---|
| 483 | return -1; |
|---|
| 484 | } |
|---|
| 485 | rc = shmctl(ucache_shmid, IPC_RMID, (struct shmid_ds *) NULL); |
|---|
| 486 | if(rc == -1) |
|---|
| 487 | { |
|---|
| 488 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 489 | "WARNING: ucache shmem_destroy: errno == %d\n", errno); |
|---|
| 490 | } |
|---|
| 491 | } |
|---|
| 492 | |
|---|
| 493 | if(dest_locks) |
|---|
| 494 | { |
|---|
| 495 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 496 | "INFO: destroying locks' shmem\n"); |
|---|
| 497 | |
|---|
| 498 | /* Destroy shmem segment containing locks */ |
|---|
| 499 | int id = SHM_ID1; |
|---|
| 500 | key_t key = ftok(KEY_FILE, id); |
|---|
| 501 | int shmflg = SVSHM_MODE; |
|---|
| 502 | int lock_shmid = shmget(key, 0, shmflg); |
|---|
| 503 | if(lock_shmid == -1) |
|---|
| 504 | { |
|---|
| 505 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 506 | "ERROR: shmget on lock_shmid returned -1\n"); |
|---|
| 507 | return -1; |
|---|
| 508 | } |
|---|
| 509 | rc = shmctl(lock_shmid, IPC_RMID, (struct shmid_ds *) NULL); |
|---|
| 510 | if(rc == -1) |
|---|
| 511 | { |
|---|
| 512 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 513 | "WARNING: ucache_locks shmem_destroy: errno == %d\n", errno); |
|---|
| 514 | } |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 518 | "INFO: both shmem segments marked for destruction.\n"); |
|---|
| 519 | |
|---|
| 520 | return rc; |
|---|
| 521 | } |
|---|
| 522 | |
|---|
| 523 | /** This program should be run as root on startup to initialize the shared |
|---|
| 524 | * memory segments required by the user cache in PVFS. |
|---|
| 525 | */ |
|---|
| 526 | int main(int argc, char **argv) |
|---|
| 527 | { |
|---|
| 528 | int rc = 0; |
|---|
| 529 | void *rp; |
|---|
| 530 | |
|---|
| 531 | gossip_enable_file(UCACHED_LOG_FILE, "a"); |
|---|
| 532 | uint64_t curr_mask; |
|---|
| 533 | int debug_on; |
|---|
| 534 | gossip_get_debug_mask(&debug_on, &curr_mask); |
|---|
| 535 | /* Enable the writing of the error message and write the message to file. */ |
|---|
| 536 | gossip_set_debug_mask(1, GOSSIP_UCACHED_DEBUG); |
|---|
| 537 | //printf("now gossip_debug_mask = 0x%016lx\n", gossip_debug_mask); |
|---|
| 538 | /* restore previous gossip_debug_mask */ |
|---|
| 539 | //gossip_set_debug_mask(debug_on, curr_mask); |
|---|
| 540 | |
|---|
| 541 | memset(locked_time, 0, (sizeof(time_t) * (BLOCKS_IN_CACHE + 1))); |
|---|
| 542 | |
|---|
| 543 | /* Direct output of ucache library, TODO: change this later */ |
|---|
| 544 | if (!out) |
|---|
| 545 | { |
|---|
| 546 | out = stdout; |
|---|
| 547 | } |
|---|
| 548 | |
|---|
| 549 | /* Continue ucached if it's the only ucached */ |
|---|
| 550 | char ps_buff1[256]; |
|---|
| 551 | char ps_buff2[256]; |
|---|
| 552 | FILE *pipe = popen("ps -e | grep -w ucached", "r"); |
|---|
| 553 | |
|---|
| 554 | /* Should catch 1 line result, but not 2 */ |
|---|
| 555 | rp = fgets(ps_buff1, 256, pipe); |
|---|
| 556 | rp = fgets(ps_buff2, 256, pipe); /* Should be zero if only 1 ucached */ |
|---|
| 557 | if(rp == NULL) |
|---|
| 558 | { |
|---|
| 559 | /* Remove old FIFOs in case daemon was killed last time */ |
|---|
| 560 | remove(FIFO1); |
|---|
| 561 | remove(FIFO2); |
|---|
| 562 | } |
|---|
| 563 | else |
|---|
| 564 | { |
|---|
| 565 | puts("FAILURE: Daemon already started"); |
|---|
| 566 | puts(ps_buff1); |
|---|
| 567 | puts(ps_buff2); |
|---|
| 568 | exit(EXIT_FAILURE); |
|---|
| 569 | } |
|---|
| 570 | |
|---|
| 571 | /* Daemonize! */ |
|---|
| 572 | rc = daemon(1, 1); |
|---|
| 573 | |
|---|
| 574 | if(rc != 0) |
|---|
| 575 | { |
|---|
| 576 | |
|---|
| 577 | perror("daemon-izing failed"); |
|---|
| 578 | exit(EXIT_FAILURE); |
|---|
| 579 | } |
|---|
| 580 | |
|---|
| 581 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 582 | "INFO: ucached started\n"); |
|---|
| 583 | |
|---|
| 584 | /* Start up with shared memory initialized */ |
|---|
| 585 | if(CREATE_AT_START) |
|---|
| 586 | { |
|---|
| 587 | run_as_child('c'); |
|---|
| 588 | atexit(clean_up); |
|---|
| 589 | } |
|---|
| 590 | |
|---|
| 591 | /* Create 2 fifos */ |
|---|
| 592 | rc = mkfifo(FIFO1, FILE_MODE); |
|---|
| 593 | if(rc != 0) |
|---|
| 594 | { |
|---|
| 595 | /* Couldn't create FIFO */ |
|---|
| 596 | return -1; |
|---|
| 597 | } |
|---|
| 598 | rc = mkfifo(FIFO2, FILE_MODE); |
|---|
| 599 | if(rc != 0) |
|---|
| 600 | { |
|---|
| 601 | /* Couldn't create FIFO */ |
|---|
| 602 | return -1; |
|---|
| 603 | } |
|---|
| 604 | |
|---|
| 605 | while(1) |
|---|
| 606 | { |
|---|
| 607 | readfd = open(FIFO1, O_RDONLY | O_NONBLOCK); |
|---|
| 608 | struct pollfd fds[1]; |
|---|
| 609 | fds[0].fd = readfd; |
|---|
| 610 | fds[0].events = POLLIN; |
|---|
| 611 | |
|---|
| 612 | rc = poll(fds, 1, FIFO_TIMEOUT * 1000); |
|---|
| 613 | |
|---|
| 614 | if(rc == -1) |
|---|
| 615 | { |
|---|
| 616 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 617 | "ERROR: poll: errno = %d\n", errno); |
|---|
| 618 | } |
|---|
| 619 | |
|---|
| 620 | if(fds[0].revents & POLLIN) |
|---|
| 621 | { |
|---|
| 622 | /* Data to be read */ |
|---|
| 623 | memset(buffer, 0, BUFF_SIZE); |
|---|
| 624 | int count = read(readfd, buffer, BUFF_SIZE); |
|---|
| 625 | while(count <= 0) |
|---|
| 626 | { |
|---|
| 627 | if(count == -1) |
|---|
| 628 | { |
|---|
| 629 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 630 | "ERROR: caught error while trying to read cmd: errno = %d\n", |
|---|
| 631 | errno); |
|---|
| 632 | } |
|---|
| 633 | /* Try to read again */ |
|---|
| 634 | count = read(readfd, buffer, BUFF_SIZE); |
|---|
| 635 | } |
|---|
| 636 | if(count > 0) |
|---|
| 637 | { |
|---|
| 638 | /* Data read into buffer*/ |
|---|
| 639 | char c = buffer[0]; |
|---|
| 640 | /* Valid Command? */ |
|---|
| 641 | if(c == 'c' || c == 'd' || c == 'x' || 'i') |
|---|
| 642 | { |
|---|
| 643 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 644 | "INFO: Command Received: %c\n", c); |
|---|
| 645 | /* Run creation in child process */ |
|---|
| 646 | if(c == 'c') |
|---|
| 647 | { |
|---|
| 648 | run_as_child(c); |
|---|
| 649 | } |
|---|
| 650 | else |
|---|
| 651 | { |
|---|
| 652 | rc = execute_cmd(c); |
|---|
| 653 | } |
|---|
| 654 | check_rc(rc); |
|---|
| 655 | } |
|---|
| 656 | /* Invalid Command */ |
|---|
| 657 | else |
|---|
| 658 | { |
|---|
| 659 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 660 | "ERROR: Invalid Command Received: %c\n", c); |
|---|
| 661 | rc = -1; |
|---|
| 662 | check_rc(rc); |
|---|
| 663 | } |
|---|
| 664 | |
|---|
| 665 | /* Data can be written, not guaranteed anything to write */ |
|---|
| 666 | int responseLength = 0; |
|---|
| 667 | if((responseLength = strlen(buffer)) != 0) |
|---|
| 668 | { |
|---|
| 669 | writefd = open(FIFO2, O_WRONLY); |
|---|
| 670 | if(writefd == -1) |
|---|
| 671 | { |
|---|
| 672 | gossip_debug(GOSSIP_UCACHED_DEBUG, |
|---|
| 673 | "ERROR: opening write FIFO: errno = %d\n", errno); |
|---|
| 674 | } |
|---|
| 675 | rc = write(writefd, buffer, BUFF_SIZE); |
|---|
| 676 | while(rc <= 0) |
|---|
| 677 | { |
|---|
| 678 | rc = write(writefd, buffer, BUFF_SIZE); |
|---|
| 679 | } |
|---|
| 680 | memset(buffer, 0, BUFF_SIZE); |
|---|
| 681 | close(writefd); |
|---|
| 682 | } |
|---|
| 683 | } |
|---|
| 684 | } |
|---|
| 685 | close(readfd); |
|---|
| 686 | |
|---|
| 687 | if(ucache_avail) |
|---|
| 688 | { |
|---|
| 689 | /* Gather stats */ |
|---|
| 690 | /* TODO: which stats? */ |
|---|
| 691 | |
|---|
| 692 | /* Write some dirty blocks out */ |
|---|
| 693 | /* TODO: create function to do this or do i already have one that will suffice? */ |
|---|
| 694 | |
|---|
| 695 | /* Check for hung locks */ |
|---|
| 696 | rc = ucached_lockchk(); |
|---|
| 697 | } |
|---|
| 698 | } |
|---|
| 699 | } |
|---|