Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/locks.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/errno.h> 9 #include <fiwix/types.h> 10 #include <fiwix/locks.h> 11 #include <fiwix/fs.h> 12 #include <fiwix/sleep.h> 13 #include <fiwix/sched.h> 14 #include <fiwix/stdio.h> 15 #include <fiwix/string.h> 16 17 static struct resource flock_resource = { NULL, NULL }; 18 19 static struct flock_file * get_new_flock(struct inode *i) 20 { 21 int n; 22 struct flock_file *ff; 23 24 lock_resource(&flock_resource); 25 26 for(n = 0; n < NR_FLOCKS; n++) { 27 ff = &flock_file_table[n]; 28 if(!ff->inode) { 29 ff->inode = i; /* mark it as busy */ 30 unlock_resource(&flock_resource); 31 return ff; 32 } 33 } 34 35 printk("WARNING: %s(): no more free slots in flock file table.\n"); 36 unlock_resource(&flock_resource); 37 return NULL; 38 } 39 40 static void release_flock(struct flock_file *ff) 41 { 42 memset_b(ff, 0, sizeof(struct flock_file)); 43 } 44 45 static struct flock_file * get_flock_file(struct inode *i, int op, struct proc *p) 46 { 47 int n; 48 struct flock_file *ff; 49 50 lock_resource(&flock_resource); 51 52 ff = NULL; 53 for(n = 0; n < NR_FLOCKS; n++) { 54 ff = &flock_file_table[n]; 55 if(ff->inode != i) { 56 continue; 57 } 58 if(p && p != ff->proc) { 59 continue; 60 } 61 break; 62 } 63 unlock_resource(&flock_resource); 64 return ff; 65 } 66 67 int posix_lock(int ufd, int cmd, struct flock *fl) 68 { 69 int n; 70 struct flock_file *ff; 71 struct inode *i; 72 unsigned char type; 73 74 lock_resource(&flock_resource); 75 i = fd_table[current->fd[ufd]].inode; 76 for(n = 0; n < NR_FLOCKS; n++) { 77 ff = &flock_file_table[n]; 78 if(ff->inode != i) { 79 continue; 80 } 81 break; 82 } 83 unlock_resource(&flock_resource); 84 if(cmd == F_GETLK) { 85 if(ff->inode == i) { 86 fl->l_type = (ff->type & LOCK_SH) ? F_RDLCK : F_WRLCK; 87 fl->l_whence = SEEK_SET; 88 fl->l_start = 0; 89 fl->l_len = 0; 90 fl->l_pid = ff->proc->pid; 91 } else { 92 fl->l_type = F_UNLCK; 93 } 94 } 95 96 switch(fl->l_type) { 97 case F_RDLCK: 98 type = LOCK_SH; 99 break; 100 case F_WRLCK: 101 type = LOCK_EX; 102 break; 103 case F_UNLCK: 104 type = LOCK_UN; 105 break; 106 default: 107 return -EINVAL; 108 } 109 if(cmd == F_SETLK) { 110 return flock_inode(i, type); 111 } 112 if(cmd == F_SETLKW) { 113 return flock_inode(i, type | LOCK_NB); 114 } 115 return 0; 116 } 117 118 void flock_release_inode(struct inode *i) 119 { 120 int n; 121 struct flock_file *ff; 122 123 lock_resource(&flock_resource); 124 for(n = 0; n < NR_FLOCKS; n++) { 125 ff = &flock_file_table[n]; 126 if(ff->inode != i) { 127 continue; 128 } 129 if(ff->proc != current) { 130 continue; 131 } 132 wakeup(ff); 133 release_flock(ff); 134 } 135 unlock_resource(&flock_resource); 136 } 137 138 int flock_inode(struct inode *i, int op) 139 { 140 int n; 141 struct flock_file *ff, *new; 142 143 if(op & LOCK_UN) { 144 if((ff = get_flock_file(i, op, current))) { 145 wakeup(ff); 146 release_flock(ff); 147 } 148 return 0; 149 } 150 151 loop: 152 lock_resource(&flock_resource); 153 new = NULL; 154 for(n = 0; n < NR_FLOCKS; n++) { 155 ff = &flock_file_table[n]; 156 if(ff->inode != i) { 157 continue; 158 } 159 if(op & LOCK_SH) { 160 if(ff->type & LOCK_EX) { 161 if(ff->proc == current) { 162 new = ff; 163 wakeup(ff); 164 break; 165 } 166 unlock_resource(&flock_resource); 167 if(op & LOCK_NB) { 168 return -EWOULDBLOCK; 169 } 170 if(sleep(ff, PROC_INTERRUPTIBLE)) { 171 return -EINTR; 172 } 173 goto loop; 174 } 175 } 176 if(op & LOCK_EX) { 177 if(ff->proc == current) { 178 new = ff; 179 continue; 180 } 181 unlock_resource(&flock_resource); 182 if(op & LOCK_NB) { 183 return -EWOULDBLOCK; 184 } 185 if(sleep(ff, PROC_INTERRUPTIBLE)) { 186 return -EINTR; 187 } 188 goto loop; 189 } 190 } 191 unlock_resource(&flock_resource); 192 193 if(!new) { 194 if(!(new = get_new_flock(i))) { 195 return -ENOLCK; 196 } 197 } 198 new->inode = i; 199 new->type = op; 200 new->proc = current; 201 202 return 0; 203 } 204 205 void flock_init(void) 206 { 207 memset_b(flock_file_table, NULL, sizeof(flock_file_table)); 208 }