Browse Source

Added write caching to devmntn

Fixed an error in diff. Put error handling in if
malloc fails to allocate write buffer

Change-Id: I0ba7908c77d55d7499ef6edda6ad9ae0035a0957
Signed-off-by: Keith Poole <keith.poole@gmail.com>
Keith Poole 8 years ago
parent
commit
9e39d5832a

+ 58 - 3
sys/src/9/port/devmntn.c

@@ -79,7 +79,7 @@ void	mountio(Mnt*, Mntrpc*);
 void	mountmux(Mnt*, Mntrpc*);
 void	mountrpc(Mnt*, Mntrpc*);
 int	rpcattn(void*);
-Chan*	mntchan(void);
+Chan*	mntchann(void);
 
 extern char	Esbadstat[];
 extern char	Enoversion[];
@@ -127,7 +127,7 @@ mntattach(char *muxattach)
 			error(Enoversion);
 	}
 
-	c = mntchan();
+	c = mntchann();
 	if(waserror()) {
 		/* Close must not be called since it will
 		 * call mnt recursively
@@ -313,6 +313,10 @@ mntopencreate(int type, Chan *c, char *name, int omode, int perm)
 	c->offset = 0;
 	c->mode = openmode(omode);
 	c->iounit = r->reply.iounit;
+	c->writeoffset = 0;
+	c->buffend = 0;
+	c->writebuff = nil;
+	c->buffsize = mnt->msize;
 	if(c->iounit == 0 || c->iounit > mnt->msize-IOHDRSZ)
 		c->iounit = mnt->msize-IOHDRSZ;
 	c->flag |= COPEN;
@@ -361,6 +365,12 @@ mntclunk(Chan *c, int t)
 static void
 mntclose(Chan *c)
 {
+	if (c->buffend > 0) {
+		mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
+	}
+	c->buffend = 0;
+	free(c->writebuff);
+	c->writebuff = nil;
 	mntclunk(c, Tclunk);
 }
 
@@ -422,6 +432,12 @@ mntread(Chan *c, void *buf, int32_t n, int64_t off)
 		return n + nc;
 	}
 
+	// Flush if we're reading this file.  Would be nice to see if
+	// read could be satisfied from buffer.
+	if (c->buffend > 0) {
+		mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
+	}
+
 	n = mntrdwr(Tread, c, buf, n, off);
 	if(isdir) {
 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
@@ -440,7 +456,46 @@ mntread(Chan *c, void *buf, int32_t n, int64_t off)
 static int32_t
 mntwrite(Chan *c, void *buf, int32_t n, int64_t off)
 {
-	return mntrdwr(Twrite, c, buf, n, off);
+	int result = n;
+	int offset = 0;
+	if (c->writebuff == nil){
+		c->writebuff = (unsigned char*)malloc(c->buffsize);
+		if(c->writebuff == nil){
+			print("devmntn: write buffer allocation of %d bytes failed\n", c->buffsize);
+			return mntrdwr(Twrite, c, buf, n, off);
+		}
+	}
+	if(off != c->writeoffset + c->buffend){
+		// non-continuous write - flush cached data
+		mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
+		c->buffend = 0;
+		c->writeoffset = off;
+	}
+	while (n + c->buffend >= c->buffsize){
+		offset = c->mux->msize - c->buffend;
+		n -= offset;
+		memmove(&c->writebuff[c->buffend], buf, offset);
+		mntrdwr(Twrite, c, c->writebuff, c->mux->msize, c->writeoffset);
+		c->writeoffset += offset;
+	}
+	memmove(&c->writebuff[c->buffend], buf + offset, n);
+	c->buffend += n;
+	return result;
+}
+
+Chan*
+mntchann(void)
+{
+        Chan *c;
+
+        c = devattach('N', 0);
+        lock(&mntalloc);
+        c->devno = mntalloc.id++;
+        unlock(&mntalloc);
+
+        if(c->mchan)
+                panic("mntchan non-zero %#p", c->mchan);
+        return c;
 }
 
 Dev mntndevtab = {

+ 4 - 0
sys/src/9/port/portdat.h

@@ -244,6 +244,10 @@ struct Chan
 	Chan*	mchan;			/* channel to mounted server */
 	Qid	mqid;			/* qid of root of mount point */
 	Path*	path;
+	unsigned char *writebuff;
+	int	buffend;
+	int	writeoffset;
+	int	buffsize;
 };
 
 struct Path

+ 1 - 1
sys/src/cmd/diff/main.c

@@ -13,7 +13,7 @@
 #include "diff.h"
 
 #define	DIRECTORY(s)		((s)->qid.type&QTDIR)
-#define	REGULAR_FILE(s)		((s)->type == 'M' && !DIRECTORY(s))
+#define	REGULAR_FILE(s)		(((s)->type == 'M' || (s)->type == 'N') && !DIRECTORY(s))
 
 Biobuf	stdout;
 

+ 14 - 2
sys/src/cmd/iozone/fileop.c

@@ -26,6 +26,7 @@
        -d <dir>  Specify starting directory.
        -U <dir>  Mount point to remount between tests.
        -t        Verbose output option.
+       -n        Single byte writes
        -v        Version information.
        -h        Help text.
  *
@@ -76,6 +77,7 @@ int verbose = 0;
 int sz = 1;
 char *mbuffer;
 int incr = 1;
+int tinywrite = 0;
 
 
 
@@ -180,6 +182,9 @@ int main(int argc, char **argv)
 			strncpy(thedir, aux, dirlen);
 			thedir[dirlen] = 0;
 			break;
+		case 'n':
+			tinywrite = 1;
+			break;
 		case 'U':
 			mountname = ARGF();
 			break;
@@ -653,7 +658,7 @@ dir_traverse(int x){
 
 void
 file_create(int x){
-	int i,j,k;
+	int i,j,k,l;
 	int fd;
 	int ret;
 	char buf[100];
@@ -703,7 +708,13 @@ file_create(int x){
 				if(stats[statCreate].speed > stats[statCreate].worst)
 					stats[statCreate].worst=stats[statCreate].speed;
 				stats[statWrite].starttime=time_so_far();
-				junk=write(fd,mbuffer,sz);
+				if(tinywrite){
+					for(l=0;l<sz;l++){
+						junk=write(fd,&mbuffer[l],1);
+					}
+				}else{
+					junk=write(fd,mbuffer,sz);
+				}
 				stats[statWrite].endtime=time_so_far();
 				stats[statWrite].counter++;
 				stats[statWrite].speed=stats[statWrite].endtime-stats[statWrite].starttime;
@@ -1145,6 +1156,7 @@ usage(void)
   print("     -d <dir>  Specify starting directory.\n");
   print("     -U <dir>  Mount point to remount between tests.\n");
   print("     -t        Verbose output option.\n");
+  print("     -n        Single byte writes\n");
   print("     -v        Version information.\n");
   print("     -h        Help text.\n");
   print("\n");

+ 106 - 0
sys/src/regress/mntn.c

@@ -0,0 +1,106 @@
+#include <u.h>
+#include <libc.h>
+
+const char *contents = "This is a string of bytes in a file"; 
+const char *changedcontents = "This is a xxxxxx of bytes in a file"; 
+const char *changedcontents2 = "This is a yyyyyy of bytes in a file"; 
+
+void
+failonbad(int rc, const char* reason)
+{
+	if(rc < 0){
+		fprint(2,"FAIL %r - %s\n", reason);
+		exits("FAIL");
+	}
+}
+
+void
+writetest()
+{
+	int rc;
+	char buffer[1000];
+	int fd = create("/n/ram/stuff", ORDWR, 0666);
+	failonbad(fd, "File open in ramdisk");
+	rc = write(fd, contents, strlen(contents));
+	if(rc != strlen(contents)){
+		failonbad(-1, "Incorrect length written");
+	}
+
+	// Check contents
+	rc = seek(fd, 0, 0);
+	failonbad(rc, "seek failed");
+	rc = read(fd, buffer, strlen(contents));
+	if(rc != strlen(contents)){
+		failonbad(-1, "Incorrect length read");
+	}
+	if(strncmp(buffer, contents, strlen(contents))){
+		failonbad(-1, "compare failed");
+	}
+
+	// update the string and verify it
+	rc = seek(fd, 10, 0);
+	failonbad(rc, "seek failed");
+	rc = write(fd, "xxxxxx", 6);
+	if (rc != 6){
+		failonbad(-1, "Incorrect update length written");
+	}
+	rc = seek(fd, 0, 0);
+	failonbad(rc, "seek failed");
+	rc = read(fd, buffer, strlen(contents));
+	if(rc != strlen(contents)){
+		failonbad(-1, "Incorrect update length read");
+	}
+	if(strncmp(buffer, changedcontents, strlen(contents))){
+		failonbad(-1, "changed compare failed");
+	}
+
+	rc = seek(fd, 10, 0);
+	failonbad(rc, "seek failed");
+	write(fd, "yyy", 3);
+	write(fd, "yyy", 3);
+	rc = seek(fd, 0, 0);
+	failonbad(rc, "seek failed");
+	rc = read(fd, buffer, strlen(contents));
+	if(rc != strlen(contents)){
+		failonbad(-1, "Incorrect update length read");
+	}
+	if(strncmp(buffer, changedcontents2, strlen(contents))){
+		failonbad(-1, "changed compare failed");
+	}
+	
+	rc = close(fd);
+	failonbad(rc, "File close in ramdisk");
+}
+
+void
+main(int argc, char *argv[])
+{
+	int rc, fd;
+	Dir* opstat;
+
+	switch(fork()){
+	case -1:
+		fprint(2, "fork fail\n");
+		exits("FAIL");
+	case 0:
+		execl("/bin/ramfs", "ramfs", "-S", "ramfs", nil);
+		fprint(2, "execl fail\n");
+		exits("execl");
+	default:
+		do{
+			sleep(10);
+			opstat = dirstat("/srv/ramfs");
+		}while (opstat == nil);
+		free(opstat);
+		fd = open("/srv/ramfs", ORDWR);
+		rc = mount(fd, -1, "/n/ram", MREPL|MCREATE, "", (int)'N');
+		if(rc < 0){
+			failonbad(-1, "mount failed");
+			exits("FAIL");
+		}
+		writetest();
+		break;
+	}
+	print("PASS\n");
+	exits("PASS");
+}

+ 1 - 0
sys/src/regress/regress.json

@@ -19,6 +19,7 @@
 			"lockt.c",
 			"longjmp.c",
 			"mixedfloat.c",
+			"mntn.c",
 			"nanotime.c",
 			"notify.c",
 			"nx.c",