/* * osprd_process_request(d, req) * Called when the user reads or writes a sector. * Should perform the read or write, as appropriate. */ static void osprd_process_request(osprd_info_t *d, struct request *req) { if (!blk_fs_request(req)) { end_request(req, 0); return; } // EXERCISE: Perform the read or write request by copying data between // our data array and the request's buffer. // Hint: The 'struct request' argument tells you what kind of request // this is, and which sectors are being read or written. // Read about 'struct request' in <linux/blkdev.h>. // Consider the 'req->sector', 'req->current_nr_sectors', and // 'req->buffer' members, and the rq_data_dir() function. // Your code here. //eprintk("Should process request...\n"); if (rq_data_dir(req) == READ) { osp_spin_lock(&d->mutex); memcpy(req->buffer, d->data + req->sector * SECTOR_SIZE, req->current_nr_sectors * SECTOR_SIZE); osp_spin_unlock(&d->mutex); } else { osp_spin_lock(&d->mutex); memcpy(d->data + req->sector * SECTOR_SIZE, req->buffer, req->current_nr_sectors * SECTOR_SIZE); osp_spin_unlock(&d->mutex); } end_request(req, 1); }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // DONE EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. if (filp->f_flags == (filp->f_flags | F_OSPRD_LOCKED)) { filp->f_flags &= ~F_OSPRD_LOCKED; if(filp_writable) { osp_spin_lock(&(d->mutex)); d->write_lock_proc = -1; d->write_lock = 0; osp_spin_unlock(&(d->mutex)); } else { osp_spin_lock(&(d->mutex)); remove_from_read(&(d->read_lock_procs), current->pid); d->read_locks--; osp_spin_unlock(&(d->mutex)); } // wake up tasks in wait queue: wake_up_all(&(d->blockq)); } // This line avoids compiler warnings; you may remove it. // (void) filp_writable, (void) d; } return 0; }
/* * osprd_process_request(d, req) * Called when the user reads or writes a sector. * Should perform the read or write, as appropriate. */ static void osprd_process_request(osprd_info_t *d, struct request *req) { if (!blk_fs_request(req)) { end_request(req, 0); return; } // EXERCISE: Perform the read or write request by copying data between // our data array and the request's buffer. // Hint: The 'struct request' argument tells you what kind of request // this is, and which sectors are being read or written. // Read about 'struct request' in <linux/blkdev.h>. // Consider the 'req->sector', 'req->current_nr_sectors', and // 'req->buffer' members, and the rq_data_dir() function. // // req->sector == Target location // req->current_nr_sectors == Number of sectors in first segment of request // req->buffer == Map of first segment // rq_data_dir() == macro to get data direction(READ or WRITE) // Your code here. int sector = (int)(req->sector); uint8_t *ptr = d->data + (sector * SECTOR_SIZE); int size = (int)(req->current_nr_sectors * SECTOR_SIZE); // DEBUG: just prints that request was received //check that the ptr didn't go "off the end" if (ptr + size > d->data + SECTOR_SIZE*nsectors) { printk(KERN_WARNING "request past the end of the device!\n"); end_request(req, 0); } //just copy the memory from the osprd_info struct to the request (it's a read) switch (rq_data_dir(req)) { case READ: osp_spin_lock(&d->mutex); memcpy(req->buffer, ptr, size); osp_spin_unlock(&d->mutex); break; case WRITE: osp_spin_lock(&d->mutex); memcpy(ptr, req->buffer, size); osp_spin_unlock(&d->mutex); break; default: //error break; } end_request(req, 1); }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. osp_spin_lock (&d->mutex); if (filp->f_flags & F_OSPRD_LOCKED) { if (filp_writable) { d->number_write_lock --; d->write_lock_holder = -1; } else { d->number_read_lock--; d->pid_list_head = list_remove_element(d->pid_list_head,current->pid); //if (d->pid_list_head == NULL) // return -ENOTTY; } } filp->f_flags = filp->f_flags & ~F_OSPRD_LOCKED; osp_spin_unlock (&d->mutex); wake_up_all (&(d->blockq)); //delete_check_deadlock_list (current->pid,d); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. osp_spin_lock(&d->mutex); if(filp->f_flags & F_OSPRD_LOCKED) { if (filp_writable != 0) d->write_locks--; else d->read_locks--; wake_up_all(&d->blockq); filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(&d->mutex); // This line avoids compiler warnings; you may remove it. // (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = ((filp->f_mode & FMODE_WRITE) != 0); int i; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. osp_spin_lock(&d->mutex); if (filp->f_flags & F_OSPRD_LOCKED) { if (filp_writable) { d->write_locked = 0; d->write_proc = -1; } else { d->num_read_locks--; for (i = 0; i < OSPRD_MAJOR; i++) { if (d->read_procs[i] == current->pid) { d->read_procs[i] = -1; break; } } } } filp->f_flags ^= F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. if (filp->f_flags & F_OSPRD_LOCKED) { if (filp_writable) { if (d->write_lock == 1) d->write_lock = 0; else eprintk("file attempted to unlock write lock it didn't have\n"); } else { osp_spin_lock(&(d->mutex)); if (d->read_lock > 0) d->read_lock--; else eprintk("file attempted to unlock read lock it didn't have\n"); osp_spin_unlock(&(d->mutex)); } } wake_up_all(&(d->blockq)); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; osp_spin_lock(&d->mutex); remove_pid_from_pid_array(d->pid_array, d->pid_count, current->pid); d->pid_count--; d->n_write_locks = 0; d->n_read_locks = 0; osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. osp_spin_lock (&d->mutex); if (filp->f_flags & F_OSPRD_LOCKED) { if (filp_writable) { d->number_write_lock --; d->write_lock_holder = -1; } else { d->number_read_lock--; int clearReturn = clear_current_reader(pid_list_head, pid_list_tail); if (clearReturn == -ENOTTY) return -ENOTTY; } } filp->f_flags = filp->f_flags & ~F_OSPRD_LOCKED; osp_spin_unlock (&d->mutex); wake_up_all (&(d->blockq)); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; pid_t pid = current->pid; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. // Check to make sure has lock if (!(filp->f_flags & F_OSPRD_LOCKED)) { return 0; } // Clear the locked flag filp->f_flags &= ~(F_OSPRD_LOCKED); // Increase the number of finished written tasks atomically if needed if(filp_writable) { osp_spin_lock(&d->mutex); d->ticket_head++; d->write_locks--; osp_spin_unlock(&d->mutex); } else { osp_spin_lock(&d->mutex); d->ticket_head++; d->read_locks--; osp_spin_unlock(&d->mutex); } // This needs to be atomic to avoid nodes removing themselves // While others are checking the same list osp_spin_lock(&g_mutex); remove_node (&d->lock_list, pid); osp_spin_unlock(&g_mutex); // We're done with the lock, notify everyone wake_up_all(&d->blockq); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. osp_spin_lock(&d->mutex); if((filp->f_flags & F_OSPRD_LOCKED) == 0) { osp_spin_unlock(&d->mutex); return 0; } else { if(filp_writable != 0) { d->write_lock = 0; d->write_lock_pid = -1; } else { d->read_locks--; // Clear this PID from the read lock list pid_list_t prev = d->read_lock_pids; pid_list_t curr = d->read_lock_pids; while(curr != NULL) { if(curr->pid == current->pid) { if(prev == NULL) d->read_lock_pids = curr->next; else prev->next = curr->next; break; } else { prev = curr; curr = curr->next; } } } wake_up_all(&d->blockq); } osp_spin_unlock(&d->mutex); // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
int check_dead_lock(int writable, osprd_info_t *d) { pid_node_t *pointer; if(writable) { osp_spin_lock(&(d->mutex)); pointer = d->write_locking_pids.head; while(pointer) { if(pointer->pid == current->pid) { osp_spin_unlock(&(d->mutex)); return 1; } pointer = pointer->next; } pointer = d->read_locking_pids.head; while(pointer) { if(pointer->pid == current->pid) { osp_spin_unlock(&(d->mutex)); return 1; } pointer = pointer->next; } } else { osp_spin_lock(&(d->mutex)); pointer = d->write_locking_pids.head; while(pointer) { if(pointer->pid == current->pid) { osp_spin_unlock(&(d->mutex)); return 1; } pointer = pointer->next; } pointer = d->read_locking_pids.head; while(pointer) { if(pointer->pid == current->pid && d->head_write == 1) { osp_spin_unlock(&(d->mutex)); return 1; } pointer = pointer->next; } } osp_spin_unlock(&(d->mutex)); return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. printk("attempting to close and release\n"); if ((filp->f_flags & F_OSPRD_LOCKED) != 0) { printk("inside filp flag\n"); osp_spin_lock(&d->mutex); filp->f_flags &= !F_OSPRD_LOCKED; if (filp_writable) { d->num_write--; d->write_pid = -1; } else { d->num_read--; pid_list_t curr = d->read_pids; // If first on the list if (current->pid == curr->pid) d->read_pids = curr->next; else { while (curr->next != NULL) { // Find pid to skip over and connect if (current->pid == curr->next->pid) { curr->next = curr->next->next; break; } else curr = curr->next; } } } wake_up_all(&d->blockq); osp_spin_unlock(&d->mutex); } // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. if(!(filp->f_flags & F_OSPRD_LOCKED)) return 0; osp_spin_lock(&d->mutex); if(filp_writable) { d->write_lock_count--; d->current_write_pid = -1; wake_up_all(&d->blockq); } else { d->read_lock_count--; process_queue_t temp = d->read_queue; process_queue_t placeholder = d->read_queue; while(placeholder != NULL) { if((placeholder->pid == current->pid) && (temp == NULL)) { d->read_queue = placeholder->next; } else if(placeholder->pid == current->pid) { temp->next = placeholder->next; break; } temp = placeholder; placeholder = placeholder->next; } wake_up_all(&d->blockq); } filp->f_flags &= ~F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
static int osprd_close_last(struct inode *inode, struct file *filp) { int r; r = 0; if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. //r = osprd_ioctl (inode, filp, OSPRDIOCRELEASE, 0); // Your code here. // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; if (!(filp->f_flags & F_OSPRD_LOCKED)) {r = -EINVAL; } // Otherwise, clear the lock from filp->f_flags, wake up // the wait queue, perform any additional accounting steps // you need, and return 0. else { osp_spin_lock(&(d->mutex)); // Clear lock flag. filp->f_flags &= ~F_OSPRD_LOCKED; //d->mutex.lock = 0; d->n_writel = 0; d->n_readl = 0; // Wake queue. if(waitqueue_active(&d->blockq) == 0){ eprintk("Tail: %d head: %d\n", d->ticket_tail, d->ticket_head); //d->ticket_head = d->ticket_tail; d->ticket_tail += d->desync; d->desync = 0; } osp_spin_unlock(&(d->mutex)); wake_up_all(&d->blockq); r = 0; } } return r; }
int check_deadlock(osprd_info_t *d) { //osp_spin_lock(&d->mutex); pid_list_t depend_head = d->check_deadlock_list_head; pid_list_t depend_tail = d->check_deadlock_list_tail; pid_list_t p = depend_head; if (p == NULL) { //osp_spin_unlock(&d->mutex); return 0; } eprintk ("haha1"); if(pid_in_list(depend_head,depend_tail,current->pid,1)) { eprintk ("before return 1"); //osp_spin_unlock(&d->mutex); return 1; } int i = 0; while(i < NOSPRD) { eprintk("in while loop"); osprd_info_t *od = &osprds[i]; if (od == d) continue; osp_spin_lock(&od->mutex); pid_list_t od_head = od->check_deadlock_list_head; pid_list_t od_tail = od->check_deadlock_list_tail; while(p!=NULL) { eprintk ("in second while loop"); if(pid_in_list(od_head,od_tail,p->pid,0)) { int count = find_pid_list(od_head,od_tail,p->pid); if(find_until_count(od_head,od_tail,current->pid,count)) { eprintk ("before return1~"); return 1; } } p = p->next; } osp_spin_unlock(&od->mutex); i++; } eprintk ("before return 0"); //osp_spin_unlock(&od->mutex); return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // if the file held a write lock, want to release it. if (filp_writable) { osp_spin_lock(&d->mutex); if (d->write_lock) { d->write_lock = 0; d->write_lock_owner = -1; } wake_up_all(&d->blockq); osp_spin_unlock(&d->mutex); } else { osp_spin_lock(&d->mutex); if (d->read_locks && (filp->f_flags & F_OSPRD_LOCKED)) d->read_locks--; if (!d->read_locks) //if this was the last lock to go wake_up_all(&d->blockq); osp_spin_unlock(&d->mutex); } // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
/* * osprd_process_request(d, req) * Called when the user reads or writes a sector. * Should perform the read or write, as appropriate. */ static void osprd_process_request(osprd_info_t *d, struct request *req) { if (!blk_fs_request(req)) { end_request(req, 0); return; } // EXERCISE: Perform the read or write request by copying data between // our data array and the request's buffer. // Hint: The 'struct request' argument tells you what kind of request // this is, and which sectors are being read or written. // Read about 'struct request' in <linux/blkdev.h>. // Consider the 'req->sector', 'req->current_nr_sectors', and // 'req->buffer' members, and the rq_data_dir() function. // Check for overwrite if (req->sector + req->current_nr_sectors > nsectors) end_request(req, 0); // If reading request if (rq_data_dir(req) == READ) { // Read to buffer sector from data memcpy (req->buffer, d->data + req->sector * SECTOR_SIZE, req->current_nr_sectors * SECTOR_SIZE); } // Writing request else if (rq_data_dir(req) == WRITE) { osp_spin_lock(&d->mutex); // Write to data sector from buffer memcpy (d->data + req->sector * SECTOR_SIZE, req->buffer, req->current_nr_sectors * SECTOR_SIZE); osp_spin_unlock(&d->mutex); } else end_request(req, 0); end_request(req, 1); }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. osp_spin_lock(&(d->mutex)); if (!pidInList(d->writeLockingPids, current->pid) && !(pidInList(d->readLockingPids, current->pid))) { osp_spin_unlock(&(d->mutex)); return -EINVAL; } if (pidInList(d->writeLockingPids, current->pid)) { removeFromList(&(d->writeLockingPids), current->pid); } if (pidInList(d->readLockingPids, current->pid)) { removeFromList(&(d->readLockingPids), current->pid); } if (d->readLockingPids == NULL && d->writeLockingPids == NULL) { filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. osp_spin_lock(&d->mutex); // When the file is closed; if ((filp->f_flags & F_OSPRD_LOCKED) != 0) { filp->f_flags &= ~F_OSPRD_LOCKED; if (filp_writable) { remove_from_list(d->write_locking_pids, current->pid); // eprintk("Write done!\n"); // print_list(d->write_locking_pids); } else { remove_from_list(d->read_locking_pids, current->pid); // eprintk("Read done!\n"); // print_list(d->read_locking_pids); } // eprintk("Locking command release!\n"); wake_up_all(&d->blockq); } osp_spin_unlock(&d->mutex); // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. // This line avoids compiler warnings; you may remove it. osp_spin_lock(&d->mutex); char wake = 't'; if(d->readlockPids->num > 1) { findpid(d->readlockPids,current->pid,'r'); wake = 'f'; } else if(d->readlockPids->num == 1) { findpid(d->readlockPids,current->pid,'r'); filp->f_flags &= ~F_OSPRD_LOCKED; } else //must be a writer..... { d->nwriters = 0; filp->f_flags &= ~F_OSPRD_LOCKED; } osp_spin_unlock(&d->mutex); if(wake == 't') wake_up_all(&d->blockq); (void) filp_writable, (void) d; return 0; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // eprintk("***************TRYING TO RELEASE*****************\n"); // Your code here. osp_spin_lock(&(d->mutex)); if(!d) return -1; if((filp->f_flags & F_OSPRD_LOCKED) == 0) { osp_spin_unlock(&(d->mutex)); return 0; } if(filp_writable) { // eprintk("***************GOING TO REMOVE*****************\n"); // osp_spin_lock(&(d->mutex)); remove_pid_list(&(d->write_locking_pids), current->pid); // eprintk("***************WRITE LOCK LENGTH: %d*****************\n", d->write_locking_pids.size); } else { // osp_spin_lock(&(d->mutex)); remove_pid_list(&(d->read_locking_pids), current->pid); } if(d->write_locking_pids.size == 0 && d->read_locking_pids.size == 0) { filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); return 0; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) //almost done static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; if (d != NULL) { osp_spinlock_t *lock = &(d->mutex); wait_queue_head_t *blockq = &(d->blockq); int readlock = in_pid_array(d->pid_read_lock, current->pid); int writelock = in_pid_array(d->pid_write_lock, current->pid); osp_spin_lock(lock); if (readlock) remove_from_pid_array(&d->pid_read_lock, current->pid); if (writelock) remove_from_pid_array(&d->pid_write_lock, current->pid); if (!readlock && !writelock) { osp_spin_unlock(lock); return -EINVAL; } if (readlock == NULL && writelock == NULL) { filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(lock); wake_up_all(blockq); } else return 1; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); if (d == NULL) return 1; osp_spin_lock(&(d->mutex)); // If the file hasn't locked the ramdisk, return -EINVAL if (!pidInList(d->writeLockingPids, current->pid) && !(pidInList(d->readLockingPids, current->pid))) { osp_spin_unlock(&(d->mutex)); return -EINVAL; } if (pidInList(d->writeLockingPids, current->pid)) { removeFromList(&d->writeLockingPids, current->pid); } if (pidInList(d->readLockingPids, current->pid)) { removeFromList(&d->readLockingPids, current->pid); } // Clear the lock from filp->f_flags if no processes (not just current process) hold any lock. if (d->readLockingPids == NULL && d->writeLockingPids == NULL) { filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. if(filp->f_flags & F_OSPRD_LOCKED) { osp_spin_lock(&d->mutex); if(filp_writable) { d->write_lock_size = 0; d->write_pid = -1; } else { d->read_lock_size--; release_read_lock(d->read_pids, NULL); } if(d->read_lock_size == 0 && d->write_lock_size ==0) wake_up_all(&d->blockq); filp->f_flags ^= F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); } // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. // lock the mutex osp_spin_lock(&(d->mutex)); if (filp_writable) { //fire the writer if (filp->f_flags&F_OSPRD_LOCKED && d->num_writer!=0) { filp->f_flags &= ~F_OSPRD_LOCKED; } d->num_writer=0; d->current_popular_writer=-1; }else{ //a reader is tired of reading if (filp->f_flags && d->num_reader!=0) { d->num_reader--; } if (d->num_reader==0) { //we can unlock if no reader is interested in reading filp->f_flags &= ~F_OSPRD_LOCKED; } } wake_up_all(&(d->blockq)); osp_spin_unlock(&(d->mutex)); // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. osp_spin_lock(&d->mutex); if (try_release_lock(d, filp, filp_writable)) { osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); } else { osp_spin_unlock(&d->mutex); } } return 0; }
// This function is called when a /dev/osprdX file is finally closed. // (If the file descriptor was dup2ed, this function is called only when the // last copy is closed.) static int osprd_close_last(struct inode *inode, struct file *filp) { if (filp) { osprd_info_t *d = file2osprd(filp); int filp_writable = filp->f_mode & FMODE_WRITE; // EXERCISE: If the user closes a ramdisk file that holds // a lock, release the lock. Also wake up blocked processes // as appropriate. // Your code here. // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; if (!(filp->f_flags & F_OSPRD_LOCKED)) return -EINVAL; // file was not locked // file is locked case: osp_spin_lock(&(d->mutex)); // lock while running and clear flag filp->f_flags = filp->f_flags & ~F_OSPRD_LOCKED; d->deadlock = 0; d->readLocks = 0; d->writeLocks = 0; int active = waitqueue_active(&d->blockq); if (active == 0) { d->ticket_tail = d->ticket_tail + d->numInterrupt; d->numInterrupt = 0; } osp_spin_unlock(&(d->mutex)); wake_up_all(&d->blockq); // wake up all tasks in blocked queue return 0; } return 0; }
/* * osprd_ioctl(inode, filp, cmd, arg) * Called to perform an ioctl on the named file. */ int osprd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { osprd_info_t *d = file2osprd(filp); // device info int r = 0; // return value: initially 0 // is file open for writing? int filp_writable = (filp->f_mode & FMODE_WRITE) != 0; // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; // Set 'r' to the ioctl's return value: 0 on success, negative on error if (cmd == OSPRDIOCACQUIRE) { // EXERCISE: Lock the ramdisk. // // If *filp is open for writing (filp_writable), then attempt // to write-lock the ramdisk; otherwise attempt to read-lock // the ramdisk. // // This lock request must block using 'd->blockq' until: // 1) no other process holds a write lock; // 2) either the request is for a read lock, or no other process // holds a read lock; and // 3) lock requests should be serviced in order, so no process // that blocked earlier is still blocked waiting for the // lock. // // If a process acquires a lock, mark this fact by setting // 'filp->f_flags |= F_OSPRD_LOCKED'. You also need to // keep track of how many read and write locks are held: // change the 'osprd_info_t' structure to do this. // // Also wake up processes waiting on 'd->blockq' as needed. // // If the lock request would cause a deadlock, return -EDEADLK. // If the lock request blocks and is awoken by a signal, then // return -ERESTARTSYS. // Otherwise, if we can grant the lock request, return 0. // 'd->ticket_head' and 'd->ticket_tail' should help you // service lock requests in order. These implement a ticket // order: 'ticket_tail' is the next ticket, and 'ticket_head' // is the ticket currently being served. You should set a local // variable to 'd->ticket_head' and increment 'd->ticket_head'. // Then, block at least until 'd->ticket_tail == local_ticket'. // (Some of these operations are in a critical section and must // be protected by a spinlock; which ones?) // Your code here (instead of the next two lines). // eprintk("Attempting to acquire\n"); // r = -ENOTTY; osp_spin_lock(&d->mutex); unsigned local_ticket = d->ticket_head++; osp_spin_unlock(&d->mutex); int wei_ret = wait_event_interruptible(d->blockq, d->write_locks == 0 && (!filp_writable || d->read_locks == 0) && d->ticket_tail == local_ticket); if(wei_ret == -ERESTARTSYS) { osp_spin_lock(&d->mutex); //if process is killed, ticket expires. //add to dead_ticket array //d->dt_len++; //d->dead_tickets[d->dt_len++] = local_ticket; d->dead_tickets[d->dt_len] = local_ticket; d->dt_len++; if (d->dt_len == d->dt_cap) { d->dt_cap *= 2; unsigned *temp_dt = kzalloc(sizeof(unsigned) *d->dt_cap, GFP_ATOMIC); memcpy(temp_dt, d->dead_tickets, sizeof(unsigned) *d->dt_len); kfree(d->dead_tickets); d->dead_tickets = temp_dt; } while (is_ticket_tail_dead(d)) { d->ticket_tail++; } osp_spin_unlock(&d->mutex); return -ERESTARTSYS; } osp_spin_lock(&d->mutex); if (filp_writable) d->write_locks++; else d->read_locks++; filp->f_flags |= F_OSPRD_LOCKED; do { d->ticket_tail++; } while (is_ticket_tail_dead(d)); osp_spin_unlock(&d->mutex); } else if (cmd == OSPRDIOCTRYACQUIRE) { // EXERCISE: ATTEMPT to lock the ramdisk. // // This is just like OSPRDIOCACQUIRE, except it should never // block. If OSPRDIOCACQUIRE would block or return deadlock, // OSPRDIOCTRYACQUIRE should return -EBUSY. // Otherwise, if we can grant the lock request, return 0. // Your code here (instead of the next two lines). osp_spin_lock(&d->mutex); if (d->write_locks == 0 && (!filp_writable || d->read_locks == 0) && d->ticket_tail == d->ticket_head) { if (filp_writable) d->write_locks++; else d->read_locks++; filp->f_flags |= F_OSPRD_LOCKED; } else r = -EBUSY; osp_spin_unlock(&d->mutex); //eprintk("Attempting to try acquire\n"); //r = -ENOTTY; } else if (cmd == OSPRDIOCRELEASE) { // EXERCISE: Unlock the ramdisk. // // If the file hasn't locked the ramdisk, return -EINVAL. // Otherwise, clear the lock from filp->f_flags, wake up // the wait queue, perform any additional accounting steps // you need, and return 0. // Your code here (instead of the next line). osp_spin_lock(&d->mutex); if (!filp->f_flags & F_OSPRD_LOCKED) r = -EINVAL; else { if (filp_writable) d->write_locks--; else d->read_locks--; wake_up_all(&d->blockq); filp->f_flags &= !F_OSPRD_LOCKED; } osp_spin_unlock(&d->mutex); //r = -ENOTTY; } else r = -ENOTTY; /* unknown command */ return r; }
int osprd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { osprd_info_t *d = file2osprd(filp); // device info int r = 0; // return value: initially 0 // is file open for writing? int filp_writable = (filp->f_mode & FMODE_WRITE) != 0; // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; // Set 'r' to the ioctl's return value: 0 on success, negative on error int my_ticket = 0; int i; if (cmd == OSPRDIOCACQUIRE) { // EXERCISE: Lock the ramdisk. // // If *filp is open for writing (filp_writable), then attempt // to write-lock the ramdisk; otherwise attempt to read-lock // the ramdisk. // // This lock request must block using 'd->blockq' until: // 1) no other process holds a write lock; // 2) either the request is for a read lock, or no other process // holds a read lock; and // 3) lock requests should be serviced in order, so no process // that blocked earlier is still blocked waiting for the // lock. // // If a process acquires a lock, mark this fact by setting // 'filp->f_flags |= F_OSPRD_LOCKED'. You also need to // keep track of how many read and write locks are held: // change the 'osprd_info_t' structure to do this. // // Also wake up processes waiting on 'd->blockq' as needed. // // If the lock request would cause a deadlock, return -EDEADLK. // If the lock request blocks and is awoken by a signal, then // return -ERESTARTSYS. // Otherwise, if we can grant the lock request, return 0. // 'd->ticket_head' and 'd->ticket_tail' should help you // service lock requests in order. These implement a ticket // order: 'ticket_tail' is the next ticket, and 'ticket_head' // is the ticket currently being served. You should set a local // variable to 'd->ticket_head' and increment 'd->ticket_head'. // Then, block at least until 'd->ticket_tail == local_ticket'. // (Some of these operations are in a critical section and must // be protected by a spinlock; which ones?) //Checking for simple deadlock if (d->write_proc == current->pid) return -EDEADLK; //int i; for (i = 0; i < OSPRD_MAJOR; i++) { if (d->read_procs[i] == current->pid) return -EDEADLK; } //if (d->write_proc == current->pid) osp_spin_lock(&d->mutex); my_ticket = d->ticket_head; d->ticket_head++; osp_spin_unlock(&d->mutex); if (filp_writable) //may be inverted for incorrect logic { r = wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket && d->write_locked == 0 && d->num_read_locked == 0); if (r == -ERESTARTSYS) { //reset_ticket_queues(my_ticket, d); if (my_ticket == d->ticket_tail) d->ticket_tail++; else d->ticket_head--; return -ERESTARTSYS; } osp_spin_lock(&d->mutex); d->write_proc = current->pid; d->write_locked = 1; } else //required for reading { r = wait_event_interruptible(d->blockq, d->ticket_tail >= my_ticket && d->write_locked == 0); if (r == -ERESTARTSYS) { if (my_ticket == d->ticket_tail) d->ticket_tail++; else d->ticket_head--; //reset_ticket_queues(my_ticket, d); return -ERESTARTSYS; } osp_spin_lock(&d->mutex); d->num_read_locked++; for (i = 0; i<OSPRD_MAJOR; i++) { if (d->read_procs[i] == -1) { d->read_procs[i] = current->pid; break; } } } d->ticket_tail++; filp->f_flags |= F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); } else if (cmd == OSPRDIOCTRYACQUIRE) { // EXERCISE: ATTEMPT to lock the ramdisk. // // This is just like OSPRDIOCACQUIRE, except it should never // block. If OSPRDIOCACQUIRE would block or return deadlock, // OSPRDIOCTRYACQUIRE should return -EBUSY. // Otherwise, if we can grant the lock request, return 0. // Your code here (instead of the next two lines). //if (d->write_proc == current->pid) // return -EBUSY; //int i; if (filp_writable) { if (d->num_read_locked > 0 || d->write_locked == 1) { return -EBUSY; } //Otherwise acquire the write lock! osp_spin_lock(&d->mutex); //my_ticket = d->ticket_head++; d->write_locked = 1; d->write_proc = current->pid; } else //again the read case { if (d->write_locked == 1) return -EBUSY; osp_spin_lock(&d->mutex); d->num_read_locked++; for (i = 0; i<OSPRD_MAJOR; i++) { if (d->read_procs[i] == -1) { d->read_procs[i] = current->pid; break; } } } d->ticket_tail++; d->ticket_head++; filp->f_flags |= F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); } else if (cmd == OSPRDIOCRELEASE) { // EXERCISE: Unlock the ramdisk. // // If the file hasn't locked the ramdisk, return -EINVAL. // Otherwise, clear the lock from filp->f_flags, wake up // the wait queue, perform any additional accounting steps // you need, and return 0. if ((filp->f_flags & F_OSPRD_LOCKED) == 0) return -EINVAL; osp_spin_lock(&d->mutex); if (filp_writable) { d->write_proc = -1; d->write_locked = 0; } else { d->num_read_locked--; for (i = 0; i<OSPRD_MAJOR; i++) { if(d->read_procs[i] == current->pid) { d->read_procs[i] = -1; break; } } } filp->f_flags ^= F_OSPRD_LOCKED; osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); r = 0; } else r = -ENOTTY; /* unknown command */ return r; }