Example #1
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, 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;
}
Example #2
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)
{

	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;
}
Example #3
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");
		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;
}