[PATCH] Fix for release of pipe buffers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

After finishing using pipes, the allocated buffers should be
freed, but the required functions were missing. The pipe
syscall allocated a new buffer on each call, until available
buffers were exhausted. Then, it returned ENFILE (NOT -ENFILE),
crashing the system.

This patch provides the missing functions and returns the
right value when buffers are not available, besides other minor
improvements to code in the fs directory.

Code size was reduced by 48 bytes.

Greetings,

Juan
diff -Nur elks.orig/fs/buffer.c elks/fs/buffer.c
--- elks.orig/fs/buffer.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/buffer.c	2014-11-28 19:01:23.000000000 -0600
@@ -31,6 +31,7 @@
 static struct wait_queue bufmapwait;	/* Wait for a free L1 buffer area */
 static struct buffer_head *bufmem_map[NR_MAPBUFS]; /* Array of bufmem's allocation */
 static __u16 _buf_ds;			/* Segment(s?) of L2 buffer cache */
+static int lastumap;
 #endif
 
 /*
@@ -176,9 +177,11 @@
 
 static struct buffer_head *get_free_buffer(void)
 {
+    register struct buffer_head *bh;
+
     for (;;) {
-	register struct buffer_head *bh = bh_lru;
-	while (bh) {
+	bh = bh_lru;
+	do {
 #ifdef CONFIG_FS_EXTERNAL_BUFFER
 	    if (bh->b_count == 0 && !bh->b_dirty && !bh->b_lock && !bh->b_data)
 #else
@@ -188,8 +191,7 @@
 		put_last_lru(bh);
 		return bh;
 	    }
-	    bh = bh->b_next_lru;
-	}
+	} while((bh = bh->b_next_lru) != NULL);
 #if 0
 	fsync_dev(0);
 	/* This causes a sleep until another process brelse's */
@@ -385,8 +387,6 @@
 
 #ifdef CONFIG_FS_EXTERNAL_BUFFER
 
-static int lastumap;
-
 /* map_buffer forces a buffer into L1 buffer space. It will freeze forever
  * before failing, so it can return void.  This is mostly 8086 dependant,
  * although the interface is not. */
@@ -521,7 +521,6 @@
 
 #ifdef CONFIG_FS_EXTERNAL_BUFFER
     _buf_ds = mm_alloc(NR_BUFFERS * 0x40);
-    lastumap = 0;
     for (i = 0; i < NR_MAPBUFS; i++)
 	bufmem_map[i] = NULL;
 #endif
diff -Nur elks.orig/fs/inode.c elks/fs/inode.c
--- elks.orig/fs/inode.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/inode.c	2014-11-28 15:22:10.000000000 -0600
@@ -22,7 +22,7 @@
 #endif
 
 static struct inode inode_block[NR_INODE];
-static struct inode *first_inode;
+static struct inode *first_inode = &inode_block[0];
 static struct wait_queue inode_wait;
 static int nr_free_inodes = NR_INODE;
 
@@ -53,7 +53,7 @@
 {
     register struct inode *inode = inode_block;
 
-    first_inode = inode->i_next = inode->i_prev = inode;
+    inode->i_next = inode->i_prev = inode;
     do {
 	insert_inode_free(++inode);
     } while (inode < &inode_block[NR_INODE-1]);
@@ -328,33 +328,33 @@
 	if (inode->i_pipe)
 	    wake_up_interruptible(&PIPE_WAIT(*inode));
 #endif
-      repeat:
-	if (inode->i_count > 1) {
-	    inode->i_count--;
-	    return;
-	}
+	goto ini_loop;
+	do {
+	    write_inode(inode);	/* we can sleep - so do again */
+	    wait_on_inode(inode);
+      ini_loop:
+	    if (inode->i_count > 1) {
+		inode->i_count--;
+		return;
+	    }
 
-	wake_up(&inode_wait);
-#ifdef NOT_YET
-	if (inode->i_pipe) {
+	    wake_up(&inode_wait);
+	    if (inode->i_pipe && inode->u.pipe_i.base) {
 	    /* Free up any memory allocated to the pipe */
-	}
-#endif
+		free_pipe_mem(inode->u.pipe_i.base);
+		inode->u.pipe_i.base = NULL;
+	    }
 
-	if (inode->i_sb) {
-	    struct super_operations *sop = inode->i_sb->s_op;
-	    if (sop && sop->put_inode) {
-		sop->put_inode(inode);
-		if (!inode->i_nlink)
-		    return;
+	    if (inode->i_sb) {
+		struct super_operations *sop = inode->i_sb->s_op;
+		if (sop && sop->put_inode) {
+		    sop->put_inode(inode);
+		    if (!inode->i_nlink)
+			return;
+		}
 	    }
-	}
 
-	if (inode->i_dirt) {
-	    write_inode(inode);	/* we can sleep - so do again */
-	    wait_on_inode(inode);
-	    goto repeat;
-	}
+	} while(inode->i_dirt);
 	inode->i_count--;
 	nr_free_inodes++;
     }
diff -Nur elks.orig/fs/ioctl.c elks/fs/ioctl.c
--- elks.orig/fs/ioctl.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/ioctl.c	2014-11-28 14:40:10.000000000 -0600
@@ -42,8 +42,6 @@
 
     if (fd >= NR_OPEN || !(filp = current->files.fd[fd]))
 	return -EBADF;
-    fop = filp->f_op;
-    filp->f_inode = filp->f_inode;
     switch (cmd) {
     case FIOCLEX:
 	FD_SET(fd, &current->files.close_on_exec);
@@ -67,6 +65,7 @@
 	if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
 	    return file_ioctl(filp, cmd, arg);
 
+	fop = filp->f_op;
 	if (fop && fop->ioctl)
 	    return fop->ioctl(filp->f_inode, filp, cmd, arg);
 
diff -Nur elks.orig/fs/minix/bitmap.c elks/fs/minix/bitmap.c
--- elks.orig/fs/minix/bitmap.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/minix/bitmap.c	2014-11-28 16:01:29.000000000 -0600
@@ -121,7 +121,7 @@
 		break;
 	    unmap_buffer(bh);
 	}
-    if (i >= 8 || !bh || j >= 8192)
+    if (i >= 8)
 	return 0;
     if (set_bit(j, bh->b_data)) {
 	panic("mnb: already set %d %d\n", j, bh->b_data);
@@ -150,7 +150,6 @@
     struct buffer_head *bh;
     register char *s;
     int n = 0;
-    ino_t ino;
 
     if (!inode)
 	return;
@@ -180,8 +179,7 @@
 	s = "nonexistent inode\n";
 	goto OUTPUT;
     }
-    ino = inode->i_ino;
-    if (!(bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
+    if (!(bh = inode->i_sb->u.minix_sb.s_imap[inode->i_ino >> 13])) {
 	s = "nonexistent imap\n";
 
       OUTPUT:
@@ -191,7 +189,7 @@
     }
     map_buffer(bh);
     clear_inode(inode);
-    if (!clear_bit((unsigned int) (ino & 8191), bh->b_data)) {
+    if (!clear_bit((unsigned int) (inode->i_ino & 8191), bh->b_data)) {
 	debug1("%s: bit %ld already cleared.\n",ino);
     }
     mark_buffer_dirty(bh, 1);
diff -Nur elks.orig/fs/minix/inode.c elks/fs/minix/inode.c
--- elks.orig/fs/minix/inode.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/minix/inode.c	2014-11-28 00:59:00.000000000 -0600
@@ -462,9 +462,6 @@
 
     if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 	inode->i_rdev = to_kdev_t(raw_inode->i_zone[0]);
-    else
-	for (block = 0; block < 9; block++)
-	    inode->i_zone[block] = raw_inode->i_zone[block];
     unmap_brelse(bh);
     minix_set_ops(inode);
 }
diff -Nur elks.orig/fs/minix/namei.c elks/fs/minix/namei.c
--- elks.orig/fs/minix/namei.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/minix/namei.c	2014-11-28 17:39:30.000000000 -0600
@@ -637,24 +637,22 @@
     struct buffer_head *bh;
 
     if (S_ISDIR(oldinode->i_mode)) {
-	iput(oldinode);
-	iput(dir);
-	return -EPERM;
+	error = -EPERM;
+	goto mlink_err;
     }
     if (oldinode->i_nlink >= MINIX_LINK_MAX) {
-	iput(oldinode);
-	iput(dir);
-	return -EMLINK;
+	error = -EMLINK;
+	goto mlink_err;
     }
     bh = minix_find_entry(dir, name, len, &de);
     if (bh) {
 	brelse(bh);
-	iput(dir);
-	iput(oldinode);
-	return -EEXIST;
+	error = -EEXIST;
+	goto mlink_err;
     }
     error = minix_add_entry(dir, name, len, &bh, &de);
     if (error) {
+      mlink_err:
 	iput(dir);
 	iput(oldinode);
 	return error;
diff -Nur elks.orig/fs/namei.c elks/fs/namei.c
--- elks.orig/fs/namei.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/namei.c	2014-11-28 07:40:56.000000000 -0600
@@ -411,7 +411,6 @@
     size_t namelen;
     int error;
 
-    mode &= ~current->fs.umask;
     error = dir_namei(filename, &namelen, &basename, NULL, &dir);
     dirp = dir;
     if (error)
@@ -427,7 +426,7 @@
 	} else {
 	    dirp->i_count++;
 	    down(&dirp->i_sem);
-	    error = iop->mknod(dirp, basename, namelen, mode, dev);
+	    error = iop->mknod(dirp, basename, namelen, (mode & ~current->fs.umask), dev);
 	    up(&dirp->i_sem);
 	}
     }
diff -Nur elks.orig/fs/open.c elks/fs/open.c
--- elks.orig/fs/open.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/open.c	2014-11-28 15:16:54.000000000 -0600
@@ -480,8 +480,7 @@
 	    current->files.fd[(int) pi] = NULL;
 	    close_fp(filp);
 	}
-	++pi;
-    } while (((int)pi) < NR_OPEN);
+    } while (((int)(++pi)) < NR_OPEN);
 }
 
 int sys_close(unsigned int fd)
diff -Nur elks.orig/fs/pipe.c elks/fs/pipe.c
--- elks.orig/fs/pipe.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/pipe.c	2014-11-30 12:01:04.455310318 -0600
@@ -31,15 +31,15 @@
 int get_unused_fd(void)
 {
     register char *pfd = 0;
+    register struct file_struct *cfs = &current->files;
 
     do {
-	if (!current->files.fd[(unsigned int) pfd]) {
+	if (!cfs->fd[(unsigned int) pfd]) {
 	    clear_bit((unsigned int) pfd,
-			     &current->files.close_on_exec);
+			     &cfs->close_on_exec);
 	    return (int) pfd;
 	}
-	++pfd;
-    } while (((int)pfd) < NR_OPEN);
+    } while (((int)(++pfd)) < NR_OPEN);
 
     return -EMFILE;
 }
@@ -76,10 +76,19 @@
     return NULL;
 }
 
+void free_pipe_mem(char *buf)
+{
+    int i;
+
+    i = ((unsigned int)pipe_base - (unsigned int)buf)/PIPE_BUF;
+    if(i < MAX_PIPES)
+	clear_bit(i, pipe_in_use);
+}
+
 static size_t pipe_read(register struct inode *inode, struct file *filp,
-		     char *buf, int count)
+		     char *buf, size_t count)
 {
-    size_t size, read = 0;
+    size_t read = 0;
     register char *chars;
 
     debug("PIPE: read called.\n");
@@ -99,18 +108,18 @@
 	    interruptible_sleep_on(&(inode->u.pipe_i.wait));
 	}
     (inode->u.pipe_i.lock)++;
-    while (count > 0 && (size = (size_t) (inode->u.pipe_i.len))) {
+    while (count > 0 && inode->u.pipe_i.len) {
 	chars = (char *)(PIPE_BUF - (inode->u.pipe_i.start));
-	if ((size_t)chars > (size_t) count)
+	if ((size_t)chars > count)
 	    chars = (char *)count;
-	if ((size_t)chars > size)
-	    chars = (char *)size;
+	if ((size_t)chars > inode->u.pipe_i.len)
+	    chars = (char *)(inode->u.pipe_i.len);
 	memcpy_tofs(buf, (inode->u.pipe_i.base+inode->u.pipe_i.start), (size_t)chars);
 	buf += (size_t)chars;
         inode->u.pipe_i.start = (inode->u.pipe_i.start + (size_t)chars)&(PIPE_BUF-1);
 	(inode->u.pipe_i.len) -= (size_t)chars;
 	read += (size_t)chars;
-	count -= (int)chars;
+	count -= (size_t)chars;
     }
     (inode->u.pipe_i.lock)--;
     wake_up_interruptible(&(inode->u.pipe_i.wait));
@@ -124,7 +133,7 @@
 }
 
 static size_t pipe_write(register struct inode *inode, struct file *filp,
-		      char *buf, int count)
+		      char *buf, size_t count)
 {
     size_t free, tmp, written = 0;
     register char *chars;
@@ -135,7 +144,7 @@
 	return -EPIPE;
     }
 
-    free = (count <= PIPE_BUF) ? (size_t) count : 1;
+    free = (count <= PIPE_BUF) ? count : 1;
     while (count > 0) {
 	while (((PIPE_BUF - (inode->u.pipe_i.len)) < free)
 	       || (inode->u.pipe_i.lock)) {
@@ -150,11 +159,11 @@
 	    interruptible_sleep_on(&(inode->u.pipe_i.wait));
 	}
 	(inode->u.pipe_i.lock)++;
-	while (count > 0 && (free = (PIPE_BUF - (inode->u.pipe_i.len)))) {
+	while (count > 0 && (free = (PIPE_BUF - inode->u.pipe_i.len))) {
 
             tmp = (inode->u.pipe_i.start + inode->u.pipe_i.len)&(PIPE_BUF-1);
 	    chars = (char *)(PIPE_BUF - tmp);
-	    if ((size_t)chars > (size_t) count)
+	    if ((size_t)chars > count)
 		chars = (char *) count;
 	    if ((size_t)chars > free)
 		chars = (char *)free;
@@ -163,7 +172,7 @@
 	    buf += (size_t)chars;
 	    (inode->u.pipe_i.len) += (size_t)chars;
 	    written += (size_t)chars;
-	    count -= (int)chars;
+	    count -= (size_t)chars;
 	}
 	(inode->u.pipe_i.lock)--;
 	wake_up_interruptible(&(inode->u.pipe_i.wait));
@@ -298,60 +307,60 @@
     struct inode *inode;
     register struct file *f1;
     register struct file *f2;
-    int error = ENFILE;
+    int error;
     int i;
 
+    inode = get_pipe_inode();
+    if (!inode)
+	goto no_inodes;
+
     /* read file */
+    error = -ENFILE;
     f1 = get_empty_filp(O_RDONLY);
     if (!f1)
 	goto no_files;
+
+    f1->f_inode = inode;
     f1->f_op = &read_pipe_fops;
 
+    error = get_unused_fd();
+    if (error < 0)
+	goto close_f1;
+    current->files.fd[error] = f1;
+    fd[0] = error;
+    i = error;
+
     /* write file */
+    error = -ENFILE;
     f2 = get_empty_filp(O_WRONLY);
     if (!f2)
-	goto close_f1;
-    f2->f_op = &write_pipe_fops;
+	goto close_f1_i;
 
-    inode = get_pipe_inode();
-    if (!inode)
-	goto close_f12;
-    f1->f_inode = f2->f_inode = inode;
-
-    error = get_unused_fd();
-    if (error < 0)
-	goto close_f12_inode;
-    i = error;
+    f2->f_inode = inode;
+    f2->f_op = &write_pipe_fops;
 
     error = get_unused_fd();
     if (error < 0)
-	goto close_f12_inode_i;
-
-    current->files.fd[i] = f1;
+	goto close_f12;
     current->files.fd[error] = f2;
-    fd[0] = i;
     fd[1] = error;
 
     return 0;
 
-  close_f12_inode_i:
-#if 0
-    put_unused_fd(error);	/* Not sure this is needed */
-#endif
-  close_f12_inode:
-#if 0
-    put_unused_fd(i);		/* Not sure this is needed */
-#endif
-    inode->i_count--;
-    iput(inode);
-
   close_f12:
     f2->f_count--;
 
+  close_f1_i:
+    current->files.fd[i] = NULL;
+
   close_f1:
     f1->f_count--;
 
   no_files:
+    inode->i_count--;
+    iput(inode);
+
+  no_inodes:
     return error;
 }
 
diff -Nur elks.orig/fs/select.c elks/fs/select.c
--- elks.orig/fs/select.c	2014-11-27 10:53:27.000000000 -0600
+++ elks/fs/select.c	2014-11-28 15:11:05.000000000 -0600
@@ -90,9 +90,10 @@
     int count;
     register __ptask currentp = current;
     fd_set set;
-    int j;
     int max = -1;
     register char *pi;
+/*
+    int j;
 
     j = 0;
     for (;;) {
@@ -115,6 +116,18 @@
 	}
     }
   end_check:
+*/
+
+    set = *in | *out | *ex;
+    for(pi = 0; set && ((int)pi < n); pi++, set >>= 1) {
+	if(!(set & 1))
+	    continue;
+	if (!currentp->files.fd[(int)pi])
+	    return -EBADF;
+	if (!currentp->files.fd[(int)pi]->f_inode)
+	    return -EBADF;
+	max = (int)pi;
+    }
     n = max + 1;
     count = 0;
   repeat:
diff -Nur elks.orig/include/linuxmt/fs.h elks/include/linuxmt/fs.h
--- elks.orig/include/linuxmt/fs.h	2014-11-27 10:53:27.000000000 -0600
+++ elks/include/linuxmt/fs.h	2014-11-27 18:09:09.000000000 -0600
@@ -510,6 +510,7 @@
 extern struct buffer_head *bread(dev_t,block_t);
 
 extern char *get_pipe_mem(void);
+extern void free_pipe_mem(char *buf);
 
 extern void mark_buffer_uptodate(struct buffer_head *,int);
 
diff -Nur elks.orig/include/linuxmt/pipe_fs_i.h elks/include/linuxmt/pipe_fs_i.h
--- elks.orig/include/linuxmt/pipe_fs_i.h	2014-11-27 10:53:27.000000000 -0600
+++ elks/include/linuxmt/pipe_fs_i.h	2014-11-28 14:16:45.000000000 -0600
@@ -5,7 +5,7 @@
     struct wait_queue wait;
     char *base;
     unsigned int start;
-    unsigned int len;
+	  size_t len;
     unsigned int lock;
     unsigned int rd_openers;
     unsigned int wr_openers;

[Index of Archives]     [Kernel]     [Linux ia64]     [DCCP]     [Linux for ARM]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux