/* * 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, char *passwd) { 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 //eprintk("cmd: %d\n", cmd); 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"); unsigned my_ticket; // check deadlock protection osp_spin_lock(&d->mutex); if (d->write_locking_pid == current->pid) { osp_spin_unlock(&d->mutex); return -EDEADLK; } my_ticket = d->ticket_head; d->ticket_head++; osp_spin_unlock(&d->mutex); //eprintk("pid = %d\n", current->pid); if (filp_writable) { //eprintk("write %d\n", d->write_locking_pid); // write lock if (wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket && d->write_locking_pid == 0 && d->read_locking_pids.size == 0 )) { //eprintk("wait_event_interruptible: %d\n", current->pid); //osp_spin_lock(&d->mutex); // if blocked if(d->ticket_tail == my_ticket) { // this process is being served d->ticket_tail = return_valid_ticket( &d->invalid_tickets, d->ticket_tail); wake_up_all(&d->blockq); } else { // not being served // add spin lock for good measure osp_spin_lock(&d->mutex); linked_list_push(&d->invalid_tickets, my_ticket); osp_spin_unlock(&d->mutex); } //osp_spin_unlock(&d->mutex); return -ERESTARTSYS; } else { // acquire the lock //eprintk("acquire write lock\n"); osp_spin_lock(&d->mutex); filp->f_flags |= F_OSPRD_LOCKED; d->write_locking_pid = current->pid; d->ticket_tail = return_valid_ticket( &d->invalid_tickets, d->ticket_tail); osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); return 0; } } else { //read lock //eprintk("read\n"); if (wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket && d->write_locking_pid == 0)) { //osp_spin_lock(&d->mutex); // if blocked if(d->ticket_tail == my_ticket) { // this process is being served d->ticket_tail = return_valid_ticket( &d->invalid_tickets, d->ticket_tail); wake_up_all(&d->blockq); } else { // not being served // add spin lock for good measure osp_spin_lock(&d->mutex); linked_list_push(&d->invalid_tickets, my_ticket); osp_spin_unlock(&d->mutex); } //osp_spin_unlock(&d->mutex); return -ERESTARTSYS; } else { // acquire the lock //eprintk("read lock\n"); osp_spin_lock(&d->mutex); filp->f_flags |= F_OSPRD_LOCKED; linked_list_push(&d->read_locking_pids, current->pid); d->ticket_tail = return_valid_ticket( &d->invalid_tickets, d->ticket_tail); osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); return 0; } } } 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). //eprintk("Attempting to try acquire\n"); if (filp_writable) { osp_spin_lock(&d->mutex); if (d->write_locking_pid != 0 || d->read_locking_pids.size != 0) { osp_spin_unlock(&d->mutex); return -EBUSY; } filp->f_flags |= F_OSPRD_LOCKED; d->write_locking_pid = current->pid; osp_spin_unlock(&d->mutex); return 0; } else { osp_spin_lock(&d->mutex); if (d->write_locking_pid != 0) { osp_spin_unlock(&d->mutex); return -EBUSY; } filp->f_flags |= F_OSPRD_LOCKED; linked_list_push(&d->read_locking_pids, current->pid); osp_spin_unlock(&d->mutex); return 0; } } else if (cmd == OSPRDIOCRELEASE) { d->passwd_hash = 0; // 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). if (!(filp->f_flags & F_OSPRD_LOCKED)) { // ramdisk isn't locked return -EINVAL; } if (filp_writable) { // see if this process has write lock osp_spin_lock(&d->mutex); if (d->write_locking_pid != current->pid) { return -EINVAL; } //eprintk("release\n"); d->write_locking_pid = 0; if (d->read_locking_pids.size == 0) { //eprintk("unsetting flag\n"); filp->f_flags ^= F_OSPRD_LOCKED; } osp_spin_unlock(&d->mutex); wake_up_all(&d->blockq); return 0; } else { //eprintk("!!!!!reached\n"); if (d->read_locking_pids.size == 0) { return -EINVAL; } osp_spin_lock(&d->mutex); int removeStatus = linked_list_remove(&d->read_locking_pids, current->pid); //eprintk("%d\n", removeStatus); if (removeStatus) { if (d->read_locking_pids.size == 0 && d->write_locking_pid == 0) { filp->f_flags ^= F_OSPRD_LOCKED; } wake_up_all(&d->blockq); //return 0; } osp_spin_unlock(&d->mutex); return removeStatus ? 0 : -EINVAL; } } else if (cmd == OSPRDIOCPASSWD) { char *buf = (char*)kmalloc(20, GFP_ATOMIC); if (copy_from_user(buf, (const char __user*) passwd, 20)) { kfree(buf); return -EFAULT; } d->passwd_hash = jenkins_hash(buf); //eprintk("OSPRDIOCPASSWD: %d\n", d->passwd_hash); return 0; } else { r = -ENOTTY; /* unknown command */ //eprintk("not recognized\n"); } return r; }
/* * 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) { int r, filp_writable; // return value: initially 0 osprd_info_t *d; r=0; d = file2osprd(filp); // device info if(!d) return -1; // is file open for writing? 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) { unsigned my_ticket; //TO DO: deadlock detection: first only check self lock //check_dead_lock() to be implemented if(check_dead_lock(filp_writable, d)) return -EDEADLK; osp_spin_lock(&(d->mutex)); my_ticket = d->ticket_head; d->head_write = filp_writable; d->ticket_head++; osp_spin_unlock(&(d->mutex)); if(filp_writable) { //write-lock //d->blockq: processes waiting on device if(wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket && d->write_locking_pids.size == 0 && d->read_locking_pids.size == 0)) { //orthogonal to w6hat d->ticket_tail is osp_spin_lock(&(d->mutex)); if(d->ticket_tail == my_ticket) { d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); wake_up_all(&(d->blockq)); } else { add_to_ticket_list(&(d->invalid_tickets), my_ticket); } osp_spin_unlock(&(d->mutex)); // wake_up_all(&(d->blockq)); return -ERESTARTSYS; } //wait_event_interruptible() returns 0 osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_pid_list(&(d->write_locking_pids), current->pid); d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); if(d->ticket_tail == d->ticket_head) d->head_write = -1; } else { //read_lock if(wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket && d->write_locking_pids.size == 0)) { // eprintk("***************SIGNAL RECEIVED*****************\n"); osp_spin_lock(&(d->mutex)); if(d->ticket_tail == my_ticket) { // eprintk("***************TAIL BEFORE IS: %d*****************\n", d->ticket_tail); d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); // eprintk("***************TAIL AFTER IS: %d*****************\n", d->ticket_tail); wake_up_all(&(d->blockq)); } else { add_to_ticket_list(&(d->invalid_tickets), my_ticket); } osp_spin_unlock(&(d->mutex)); // wake_up_all(&(d->blockq)); return -ERESTARTSYS; } // eprintk("***************GOING TO GET READ LOCK*****************\n"); osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_pid_list(&(d->read_locking_pids), current->pid); d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); if(d->ticket_tail == d->ticket_head) d->head_write = -1; } osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); return 0; // 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; } else if (cmd == OSPRDIOCTRYACQUIRE) { // eprintk("hehe"); if(check_dead_lock(filp_writable, d)) return -EBUSY; if(filp_writable) { osp_spin_lock(&(d->mutex)); if(!(d->ticket_tail == d->ticket_head && d->write_locking_pids.size == 0 && d->read_locking_pids.size == 0)) { osp_spin_unlock(&(d->mutex)); return -EBUSY; } filp->f_flags |= F_OSPRD_LOCKED; d->ticket_head++; add_to_pid_list(&(d->write_locking_pids), current->pid); d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); if(d->ticket_tail == d->ticket_head) d->head_write = -1; } else { osp_spin_lock(&(d->mutex)); if(!(d->ticket_tail == d->ticket_head && d->write_locking_pids.size == 0)) { osp_spin_unlock(&(d->mutex)); return -EBUSY; } filp->f_flags |= F_OSPRD_LOCKED; d->ticket_head++; add_to_pid_list(&(d->read_locking_pids), current->pid); d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1); if(d->ticket_tail == d->ticket_head) d->head_write = -1; } osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); return 0; // 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). // eprintk("Attempting to try acquire\n"); // r = -ENOTTY; } else if (cmd == OSPRDIOCRELEASE) { // eprintk("***************TRYING TO RELEASE*****************\n"); if((filp->f_flags & F_OSPRD_LOCKED) == 0) return -EINVAL; //write list has at most 1 element //read list can have multiple elements but they don't need to block each other if(filp_writable) { // eprintk("***************RELEASING WRITE LOCK*****************\n"); osp_spin_lock(&(d->mutex)); remove_pid_list(&(d->write_locking_pids), current->pid); } 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; // EXERCISE: Unlock the ramdisk. // (process) // 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). // r = -ENOTTY; } else if (cmd == OSPRDWATCHER) { int u_offset, u_end, u_info_type, disp_start, disp_end; void __user *argp; msg_t *msgr; msgr = (msg_t*)kmalloc(sizeof(msg_t), GFP_ATOMIC); argp = (void __user *) arg; if(copy_from_user((char *)msgr, (char *)argp, sizeof(*msgr))!=0) { eprintk("Copy from user failed!\n"); } u_info_type = msgr->w_type; if(u_info_type == 's') { u_offset = atoi(msgr->u_offset) * SECTOR_SIZE; u_end = (atoi(msgr->u_end) + 1) * SECTOR_SIZE; } else if(u_info_type == 'S') { u_offset = atoi(msgr->u_offset) * SECTOR_SIZE; u_end = atoi(msgr->u_end) * SECTOR_SIZE; } else if (u_info_type == 'b') { u_offset = atoi(msgr->u_offset); u_end = atoi(msgr->u_end); } else { u_offset = 0; u_end = 0x7FFFFFFF; } d->info_flag = 0; // eprintk("***********u_offset: %d, u_end: %d, d->info_flag: %d, d->info_byte_offset: %d, d->info_byte_size: %d\n", u_offset, u_end, d->info_flag, d->info_byte_offset, d->info_byte_size); while(1) { // eprintk("**************hohoho***************\n"); if(wait_event_interruptible(d->blockq, d->info_flag != 0 && !(u_offset > d->info_byte_offset + d->info_byte_size || d->info_byte_offset >= u_end))) { eprintk("QUITING RAMDISK WATCHER!\n"); osp_spin_lock(&(d->mutex)); d->info_flag = 0; d->info_byte_offset = 0; d->info_byte_size = 0; osp_spin_unlock(&(d->mutex)); kfree(msgr); return 0; } // eprintk("***********WAKING UP***********\n"); osp_spin_lock(&(d->mutex)); // eprintk("***********u_offset: %d, u_end: %d, d->info_flag: %d, d->info_byte_offset: %d, d->info_byte_size: %d\n", u_offset, u_end, d->info_flag, d->info_byte_offset, d->info_byte_size); disp_start = (d->info_byte_offset > u_offset)? d->info_byte_offset:u_offset; disp_end = (d->info_byte_offset + d->info_byte_size > u_end)? u_end:d->info_byte_offset + d->info_byte_size; if(u_info_type == 's') { if(d->info_flag == 1) { eprintk("RAMDISK MESSAGE: writting on sector %d.\n", disp_start / SECTOR_SIZE); } else { eprintk("RAMDISK MESSAGE: reading on sector %d.\n", disp_start / SECTOR_SIZE); } } else if(u_info_type == 'S') { if(d->info_flag == 1) { eprintk("RAMDISK MESSAGE: writting on sector %d to sector %d.\n", disp_start / SECTOR_SIZE, disp_end / SECTOR_SIZE); } else { eprintk("RAMDISK MESSAGE: reading on sector %d to sector %d.\n", disp_start / SECTOR_SIZE, disp_end / SECTOR_SIZE); } } else if(u_info_type == 'b') { if(d->info_flag == 1) { eprintk("RAMDISK MESSAGE: writting on byte %d.\n", disp_start); } else { eprintk("RAMDISK MESSAGE: reading on byte %d.\n", disp_start); } } else { if(d->info_flag == 1) { eprintk("RAMDISK MESSAGE: writting on byte %d to byte %d.\n", disp_start, disp_end); } else { eprintk("RAMDISK MESSAGE: reading on byte %d to byte %d.\n", disp_start, disp_end); } } d->info_flag = 0; d->s_change = 0; osp_spin_unlock(&(d->mutex)); } } else r = -ENOTTY; /* unknown command */ return r; }
/* * 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"); unsigned my_ticket; // TODO DEADLOCK DETECTION if(d->write_locking_pids->head!=NULL && current->pid == d->write_locking_pids->head->num){ return -EDEADLK; } osp_spin_lock(&(d->mutex)); my_ticket = d->ticket_head; d->ticket_head++; osp_spin_unlock(&(d->mutex)); if(filp_writable){ //write-lock //if the condition is true, the function returns 0 //otherwise, block, no value returned //if it receives a signal, it returns non-zero value //blockq stores processes that are waiting on the current device if(wait_event_interruptible(d->blockq,d->ticket_tail == my_ticket && d->write_locking_pids->size == 0 && d->read_locking_pids->size == 0)){ //don't give lock, enter the if statement only when you receive a signal //kill current process and store its ticket number into invalid ticket list //osp_spin_lock(&(d->mutex)); if(d->ticket_tail == my_ticket){ //the current process is the next one to have the lock, but we receive kill sginal //find the next valid ticket //return_valid_ticket function returns the next valid ticket d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); //wake_up_all(&(d->blockq)); } else{ add_to_ticket_list(d->invalid_tickets,my_ticket); //no need to change the ticket tail } //osp_spin_unlock(&(d->mutex)); return -ERESTARTSYS; } //wait_event_interruptible() returns 0 //the current process can get the lock on the device osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_ticket_list(d->write_locking_pids, current->pid); //increase ticket tail to be the next valid ticket d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); return 0; } else{ //read-lock //multiple processes can have read lock on one device if(wait_event_interruptible(d->blockq,d->ticket_tail == my_ticket && d->write_locking_pids->size == 0)){ osp_spin_lock(&(d->mutex)); if(d->ticket_tail == my_ticket){ d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); } else{ add_to_ticket_list(d->invalid_tickets,my_ticket); } osp_spin_unlock(&(d->mutex)); return -ERESTARTSYS; } //wait_event_interruptible() returns 0 //the current process can get the lock on the device osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_ticket_list(d->read_locking_pids, current->pid); //increase ticket tail to be the next valid ticket d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); osp_spin_unlock(&(d->mutex)); wake_up_all(&(d->blockq)); return 0; } } 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). unsigned my_ticket; // TODO DEADLOCK DETECTION osp_spin_lock(&(d->mutex)); my_ticket = d->ticket_head; d->ticket_head++; osp_spin_unlock(&(d->mutex)); if(filp_writable){ //write-lock //if the condition is true, the function returns 0 //otherwise, block, no value returned //if it receives a signal, it returns non-zero value //blockq stores processes that are waiting on the current device if(!(d->blockq,d->ticket_tail == my_ticket && d->write_locking_pids->size == 0 && d->read_locking_pids->size == 0) ){ d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); return -EBUSY; } //wait_event_interruptible() returns 0 //the current process can get the lock on the device osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_ticket_list(d->write_locking_pids, current->pid); //increase ticket tail to be the next valid ticket d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); osp_spin_unlock(&(d->mutex)); } else{ //read-lock //multiple processes can have read lock on one device if(!(d->blockq,d->ticket_tail == my_ticket && d->write_locking_pids->size == 0) ){ d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); return -EBUSY; } //wait_event_interruptible() returns 0 //the current process can get the lock on the device osp_spin_lock(&(d->mutex)); filp->f_flags |= F_OSPRD_LOCKED; add_to_ticket_list(d->read_locking_pids, current->pid); //increase ticket tail to be the next valid ticket d->ticket_tail = return_valid_ticket(d->invalid_tickets, d->ticket_tail+1); osp_spin_unlock(&(d->mutex)); } wake_up_all(&d->blockq); return 0; //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). if((filp->f_flags & F_OSPRD_LOCKED) == 0) return -EINVAL; osp_spin_lock(&(d->mutex)); if (filp_writable) { remove_from_list(d->write_locking_pids,current->pid); } else { remove_from_list(d->read_locking_pids,current->pid); } filp->f_flags &= !F_OSPRD_LOCKED; osp_spin_unlock(&(d->mutex)); wake_up_all (&d->blockq); } else r = -ENOTTY; /* unknown command */ return r; }