pipe: redo reader/writer counting
authorAlan Cox <alan@linux.intel.com>
Mon, 29 Aug 2016 10:54:01 +0000 (11:54 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 29 Aug 2016 10:54:01 +0000 (11:54 +0100)
It's almost as cheap to keep counters as go scanning each time in terms of
memory usage and much much faster.

Kernel/filesys.c
Kernel/include/kernel.h
Kernel/inode.c
Kernel/syscall_fs.c
Kernel/syscall_fs3.c
Kernel/syscall_net.c

index 2dfdde6..57ac39c 100644 (file)
@@ -687,21 +687,6 @@ int8_t oft_alloc(void)
     return -1;
 }
 
-/*     Check if an inode is open for reading or for writing. Needed for pipe
- *     EOF and will one day be needed for shared code segments (8086 etc)
- */
-int8_t oft_inuse(inoptr ino, uint8_t rw)
-{
-    struct oft *ofptr = of_tab;
-    while(ofptr <= &of_tab[OFTSIZE - 1]) {
-        if (ofptr->o_refs && ofptr->o_inode == ino &&
-            O_ACCMODE(ofptr->o_access) != rw)
-            return 1;
-        ofptr++;
-    }
-    return 0;
-}
-
 /*
  *     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,
index 3ecf6ea..d425c33 100644 (file)
@@ -219,12 +219,15 @@ struct hd_geometry {
 #define major(x) ((x) >> 8)
 #define minor(x) ((x) & 0xFF)
 
-typedef struct cinode { // note: exists in memory *and* on disk
-    uint16_t   c_magic;           /* Used to check for corruption. */
-    uint16_t   c_dev;             /* Inode's device */
-    uint16_t   c_num;             /* Inode # */
-    dinode     c_node;
-    uint8_t    c_refs;            /* In-core reference count */
+/* In memory inode structure */
+typedef struct cinode {
+    uint16_t   c_magic;         /* Used to check for corruption. */
+    uint16_t   c_dev;           /* Inode's device */
+    uint16_t   c_num;           /* Inode # */
+    dinode     c_node;         /* On disk inode data */
+    uint8_t    c_refs;          /* In-core reference count */
+    uint8_t    c_readers;      /* Count of readers by oft entry */
+    uint8_t    c_writers;      /* Count of writers by oft entry */
     uint8_t    c_flags;           
 #define CDIRTY         0x80    /* Modified flag. */
 #define CRDONLY                0x40    /* On a read only file system */
@@ -776,11 +779,6 @@ extern void i_free(uint16_t devno, uint16_t ino);
 extern blkno_t blk_alloc(uint16_t devno);
 extern void blk_free(uint16_t devno, blkno_t blk);
 extern int8_t oft_alloc(void);
-extern int8_t oft_inuse(inoptr ino, uint8_t rw);
-/* Yes these are intentionally backwards - there are 3 modes so the loop looks
-   for "not this mode" */
-#define INUSE_R                O_WRONLY
-#define INUSE_W                O_RDONLY
 extern void deflock(struct oft *ofptr);
 extern void oft_deref(int8_t of);
 /* returns index of slot, or -1 on failure */
index dc0f2ac..84cf696 100644 (file)
    how we handle the psleep_flags bit */
 static uint8_t pipewait(inoptr ino, uint8_t flag)
 {
-        int8_t n;
         while(ino->c_node.i_size == 0) {
-                n = oft_inuse(ino, INUSE_W);
-                if (n == 0 || psleep_flags(ino, flag)) {
+                if (ino->c_writers == 0 || psleep_flags(ino, flag)) {
                         udata.u_count = 0;
                         return 0;
                 }
@@ -164,7 +162,7 @@ void writei(inoptr ino, uint8_t flag)
                   in one go - needs merging into the loop */
                while ((towrite = udata.u_count) > (16 * BLKSIZE) - 
                                        ino->c_node.i_size) {
-                       if (!oft_inuse(ino, INUSE_R)) { /* No readers */
+                       if (ino->c_readers == 0) {      /* No readers */
                                udata.u_count = (usize_t)-1;
                                udata.u_error = EPIPE;
                                ssig(udata.u_ptab, SIGPIPE);
@@ -238,18 +236,22 @@ void writei(inoptr ino, uint8_t flag)
 int16_t doclose(uint8_t uindex)
 {
        int8_t oftindex;
+       struct oft *oftp;
        inoptr ino;
        uint16_t flush_dev = NO_DEVICE;
+       uint8_t m;
 
        if (!(ino = getinode(uindex)))
                return (-1);
 
        oftindex = udata.u_files[uindex];
+       oftp = of_tab + udata.u_files[uindex];
+       m = O_ACCMODE(oftp->o_access);
 
-       if (of_tab[oftindex].o_refs == 1) {
+       if (oftp->o_refs == 1) {
                if (isdevice(ino))
                        d_close((int) (ino->c_node.i_addr[0]));
-               if (getmode(ino) == MODE_R(F_REG) && O_ACCMODE(of_tab[oftindex].o_access))
+               if (getmode(ino) == MODE_R(F_REG) && m)
                        flush_dev = ino->c_dev;
 #ifdef CONFIG_NET
                if (issocket(ino))
@@ -260,6 +262,11 @@ int16_t doclose(uint8_t uindex)
        udata.u_cloexec &= ~(1 << uindex);
        oft_deref(oftindex);
 
+       if (m != O_RDONLY)
+               ino->c_writers--;
+        if (m != O_WRONLY)
+                ino->c_readers--;
+
        /* if we closed a file in write mode, flush the device's cache after inode has been deferenced */
        if(flush_dev != NO_DEVICE)
                d_flush(flush_dev);
index 10d7c55..db58a8c 100644 (file)
@@ -337,6 +337,8 @@ arg_t _pipe(void)
        ++ino->c_refs;
        ino->c_node.i_mode = F_PIPE | 0777;     /* No permissions necessary on pipes */
        ino->c_node.i_nlink = 0;        /* a pipe is not in any directory */
+       ino->c_readers++;
+       ino->c_writers++;
 
        // write results to userspace
        uputw(u1, fildes);
index 2f63b4f..9cdf2f9 100644 (file)
@@ -128,8 +128,13 @@ arg_t _open(void)
        of_tab[oftindex].o_access = flag;       /* Save the low bits only */
        if (flag & O_CLOEXEC)
                udata.u_cloexec |= (1 << oftindex);
-       /* FIXME: ATIME ? */
 
+       if (O_ACCMODE(flag) != O_RDONLY)
+               ino->c_writers++;
+       if (O_ACCMODE(flag) != O_WRONLY)
+               ino->c_readers++;
+
+       /* FIXME: ATIME ? */
 /*
  *         Sleep process if no writer or reader
  */
index 58c7a93..1beab3e 100644 (file)
@@ -324,6 +324,8 @@ arg_t make_socket(struct sockinfo *s, struct socket **np)
        /* The nlink cheat needs to be taught to fsck! */
        ino->c_node.i_mode = F_SOCK | 0777;
        ino->c_node.i_nlink = n->s_num; /* Cheat !! */
+       ino->c_readers = 1;
+       ino->c_writers = 1;
 
        of_tab[oftindex].o_inode = ino;
        of_tab[oftindex].o_access = O_RDWR;