ip->c_node.i_mode);
kprintf("%d\t%d\t%d\t%d\n", /* line split for compiler */
ip->c_node.i_nlink, ip->c_node.i_addr[0],
- ip->c_refs, ip->c_dirty);
+ ip->c_refs, ip->c_flags);
if (!ip->c_magic)
break;
}
if(udata.u_error)
return false;
- setftime(wd, A_TIME|M_TIME|C_TIME); /* Sets c_dirty */
+ setftime(wd, A_TIME|M_TIME|C_TIME); /* Sets CDIRTY */
/* Update file length to next block */
if(wd->c_node.i_size & BLKMASK)
return -1;
}
+/*
+ * To minimise storage we don't track exclusive locks explicitly. We know
+ * that if we are dropping an exclusive lock then we must be the owner,
+ * and if we are dropping a lock that is not exclusive we must own one of
+ * the non exclusive locks.
+ */
+void deflock(struct oft *ofptr)
+{
+ inoptr i = ofptr->o_inode;
+ uint8_t c = i->c_flags & CFLOCK;
+ if (ofptr->o_access & O_FLOCK) {
+ if (c == CFLEX)
+ c = 0;
+ else
+ c--;
+ i->c_flags = (i->c_flags & ~CFLOCK) | c;
+ wakeup(&i->c_flags);
+ }
+}
+
+/*
+ * Drop a reference in the open file table. If this is the last reference
+ * from a user file table then drop any file locks, dereference the inode
+ * and mark empty
+ */
void oft_deref(int8_t of)
{
struct oft *ofptr;
ofptr = of_tab + of;
if(!(--ofptr->o_refs) && ofptr->o_inode) {
+ deflock(ofptr);
i_deref(ofptr->o_inode);
ofptr->o_inode = NULLINODE;
}
f_trunc(ino);
/* If the inode was modified, we must write it to disk. */
- if(!(ino->c_refs) && ino->c_dirty)
+ if(!(ino->c_refs) && (ino->c_flags & CDIRTY))
{
if(!(ino->c_node.i_nlink))
{
buf =(struct dinode *)bread(ino->c_dev, blkno,0);
memcpy((char *)((char **)&buf[ino->c_num & 0x07]), (char *)(&ino->c_node), 64);
bfree((bufptr)buf, 2);
- ino->c_dirty = false;
+ ino->c_flags &= ~CDIRTY;
}
memset((char *)ino->c_node.i_addr, 0, sizeof(ino->c_node.i_addr));
- ino->c_dirty = true;
+ ino->c_flags |= CDIRTY;
ino->c_node.i_size = 0;
}
if(rwflg ||(nb = blk_alloc(dev))==0)
return(NULLBLK);
ip->c_node.i_addr[bn] = nb;
- ip->c_dirty = true;
+ ip->c_flags |= CDIRTY;
}
return(nb);
}
if(rwflg || !(nb = blk_alloc(dev)))
return(NULLBLK);
ip->c_node.i_addr[20-j] = nb;
- ip->c_dirty = true;
+ ip->c_flags |= CDIRTY;
}
/* fetch through the indirect blocks
*/
void setftime(inoptr ino, uint8_t flag)
{
- ino->c_dirty = true;
+ ino->c_flags |= CDIRTY;
if(flag & A_TIME)
rdtime32(&(ino->c_node.i_atime));
uint16_t c_num; /* Inode # */
dinode c_node;
uint8_t c_refs; /* In-core reference count */
- bool c_dirty; /* Modified flag. */
+ uint8_t c_flags;
+#define CDIRTY 0x80 /* Modified flag. */
+#define CFLOCK 0x0F /* flock bits */
+#define CFLEX 0x0F /* locked exclusive */
+#define CFMAX 0x0E /* highest shared lock count permitted */
} cinode, *inoptr;
#define NULLINODE ((inoptr)NULL)
#define O_APPEND 4
#define O_SYNC 8
#define O_NDELAY 16
+#define O_FLOCK 128 /* Cannot be user set */
#define O_CREAT 256
#define O_EXCL 512
#define O_TRUNC 1024
#define O_NOCTTY 2048
#define O_CLOEXEC 4096
-#define O_BADBITS (32 | 64 | 128 | 8192 | 16384 | 32768U)
+#define O_BADBITS (32 | 64 | O_FLOCK | 8192 | 16384 | 32768U)
#define F_GETFL 0
#define F_SETFL 1
#define FNDELAY O_NDELAY
+#define LOCK_SH 0
+#define LOCK_EX 1
+#define LOCK_UN 2 /* Must be highest */
+
+#define LOCK_NB O_NDELAY /* Must be O_NDELAY */
/*
* Error codes
#define EDOM 33 /* Argument too large */
#define ERANGE 34 /* Result too large */
-#define EWOULDBLOCK 35 /* Operation would block */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOLCK 35 /* Lock table full */
#define ENOTEMPTY 36 /* Directory is not empty */
#define ENAMETOOLONG 37 /* File name too long */
CODE1 blkno_t blk_alloc(uint16_t devno);
CODE1 void blk_free(uint16_t devno, blkno_t blk);
CODE1 int8_t oft_alloc(void);
+CODE1 void deflock(struct oft *ofptr);
CODE1 void oft_deref(int8_t of);
/* returns index of slot, or -1 on failure */
CODE1 int8_t uf_alloc(void);
CODE2 int16_t _fchdir(void); /* FUZIX system call 48 */
CODE2 int16_t _fchmod(void); /* FUZIX system call 49 */
CODE2 int16_t _fchown(void); /* FUZIX system call 50 */
-CODE2 int16_t _mkdir(void); /* FUZIX system call 51 */
+CODE2 int16_t _mkdir(void); /* FUZIX system call 51 */
CODE2 int16_t _rmdir(void); /* FUZIX system call 52 */
-CODE2 int16_t _setpgrp(void); /* FUZIX system call 53 */
-CODE2 int16_t _uname(void); /* FUZIX system call 54 */
-CODE2 int16_t _waitpid(void); /* FUZIX system call 55 */
-CODE2 int16_t _profil(void); /* FUZIX system call 56 */
-CODE2 int16_t _uadmin(void); /* FUZIX system call 57 */
+CODE2 int16_t _setpgrp(void); /* FUZIX system call 53 */
+CODE2 int16_t _uname(void); /* FUZIX system call 54 */
+CODE2 int16_t _waitpid(void); /* FUZIX system call 55 */
+CODE2 int16_t _profil(void); /* FUZIX system call 56 */
+CODE2 int16_t _uadmin(void); /* FUZIX system call 57 */
CODE2 int16_t _nice(void); /* FUZIX system call 58 */
-CODE2 int16_t _sigdisp(void); /* FUZIX system call 59 */
+CODE2 int16_t _sigdisp(void); /* FUZIX system call 59 */
+CODE2 int16_t _flock(void); /* FUZIX system call 60 */
+
#endif /* __FUZIX__KERNEL_DOT_H__ */
-#define NR_SYSCALL 60
+#define NR_SYSCALL 61
char *syscall_name[NR_SYSCALL] = {
"_exit",
"uadmin",
"nice",
"_sigdisp",
+ "flock",
};
int syscall_args[NR_SYSCALL] = {
4, //_profil
3, //uadmin
1, //nice
- 2 //_sigdisp
+ 2, //_sigdisp
+ 2, //flock
};
}
#undef buf
+
+/**************************************
+flock(fd, lockop) Function 60
+int file;
+int lockop;
+
+Perform locking upon a file.
+**************************************/
+
+#define file (uint16_t)udata.u_argn
+#define lockop (uint16_t)udata.u_argn1
+
+int16_t _flock(void)
+{
+ inoptr ino;
+ struct oft *o;
+ staticfast uint8_t c;
+ staticfast uint8_t lock = lockop & ~LOCK_NB;
+ staticfast int self;
+
+ self = 0;
+
+ if (lock > LOCK_UN) {
+ udata.u_error = EINVAL;
+ return -1;
+ }
+
+ if ((ino = getinode(file)) == NULLINODE)
+ return -1;
+ o = &of_tab[udata.u_files[file]];
+
+ c = ino->c_flags & CFLOCK;
+
+ /* Upgrades and downgrades. Check if we are in fact doing a no-op */
+ if (o->o_access & O_FLOCK) {
+ self = 1;
+ /* Shared or exclusive to shared can't block and is easy */
+ if (lock == LOCK_SH) {
+ if (c == CFLEX)
+ c = 1;
+ goto done;
+ }
+ /* Exclusive to exclusive - no op */
+ if (c == CFLEX && lock == LOCK_EX)
+ return 0;
+ /* Shared to exclusive - handle via the loop */
+ }
+
+
+ /* Unlock - drop the locks, mark us not a lock holder. Doesn't block */
+ if (lockop == LOCK_UN) {
+ o->o_access &= ~O_FLOCK;
+ deflock(o);
+ return 0;
+ }
+
+ do {
+ /* Exclusive lock must have no holders */
+ if (c == self && lock == LOCK_EX) {
+ c = CFLEX;
+ goto done;
+ }
+ if (c < CFMAX) {
+ c++;
+ goto done;
+ }
+ if (c == CFMAX) {
+ udata.u_error = ENOLCK;
+ return -1;
+ }
+ /* LOCK_NB is defined as O_NDELAY... */
+ if (psleep_flags(&ino->c_flags, (lockop & LOCK_NB)))
+ return -1;
+ /* locks will hopefully have changed .. */
+ c = ino->c_flags & CFLOCK;
+ } while (1);
+
+done:
+ if (o->o_access & O_FLOCK)
+ deflock(o);
+ ino->c_flags &= ~CFLOCK;
+ ino->c_flags |= c;
+ o->o_access |= O_FLOCK;
+ wakeup(&ino->c_flags);
+ return 0;
+}
+
+
+#undef file
+#undef lockop
\ No newline at end of file