From 390e94b1eafeeafef096eff57f2436ef77d1f18c Mon Sep 17 00:00:00 2001
From: pschwan <pschwan>
Date: Mon, 11 Mar 2002 14:58:49 +0000
Subject: [PATCH] - a few more header cleanups - removed some unused code -
 inserted many extra BUG()s to catch problems early - fixed a use of the
 incorrect inode, and fixed the directory bug - enabled mds_open/mds_close -
 fixed a small leak in an error case - removed an extra set_page_dirty() in
 the write path - added an
 open/write/close/open/unlink/read/truncate/write/read/close test

---
 lustre/include/linux/lustre_light.h |  84 -------------------
 lustre/lib/page.c                   |   4 -
 lustre/llite/dir.c                  |   6 +-
 lustre/llite/file.c                 |  25 +++---
 lustre/llite/namei.c                |   4 +-
 lustre/llite/rw.c                   |  58 +++++++------
 lustre/mds/handler.c                |  14 +++-
 lustre/mds/mds_reint.c              |  19 +++--
 lustre/tests/Makefile.am            |   3 +-
 lustre/tests/llmount.sh             |   2 +-
 lustre/tests/openunlink.c           | 122 ++++++++++++++++++++++++++++
 11 files changed, 203 insertions(+), 138 deletions(-)
 create mode 100644 lustre/tests/openunlink.c

diff --git a/lustre/include/linux/lustre_light.h b/lustre/include/linux/lustre_light.h
index 4ebe4dc17d..b4a2c23306 100644
--- a/lustre/include/linux/lustre_light.h
+++ b/lustre/include/linux/lustre_light.h
@@ -66,31 +66,7 @@ static inline struct obd_conn *ll_i2obdconn(struct inode *inode)
 	return &(ll_i2sbi(inode))->ll_conn;
 }
 
-
-
-
-
-/* super.c */ 
-struct ll_pgrq {
-        struct list_head         rq_plist;      /* linked list of req's */
-        unsigned long            rq_jiffies;
-        struct page             *rq_page;       /* page to be written */
-};
-
-extern struct list_head ll_super_list;       /* list of all LL superblocks */
-
-
-
 /* dir.c */
-#define EXT2_DIR_PAD                    4
-#define EXT2_DIR_ROUND                  (EXT2_DIR_PAD - 1)
-#define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
-                                         ~EXT2_DIR_ROUND)
-#define EXT2_NAME_LEN 255
-
-int ll_check_dir_entry (const char * function, struct inode * dir,
-                        struct ext2_dir_entry_2 * de, struct page * page,
-                        unsigned long offset);
 extern struct file_operations ll_dir_operations;
 extern struct inode_operations ll_dir_inode_operations;
 
@@ -98,71 +74,11 @@ extern struct inode_operations ll_dir_inode_operations;
 extern struct file_operations ll_file_operations;
 extern struct inode_operations ll_file_inode_operations;
 
-/* flush.c */
-void ll_dequeue_pages(struct inode *inode);
-int ll_flushd_init(void);
-int ll_flushd_cleanup(void);
-int ll_flush_reqs(struct list_head *inode_list, unsigned long check_time);
-int ll_flush_dirty_pages(unsigned long check_time);
-
-/* namei.c */
-/*
- * Structure of the super block
- */
-
-
-#define EXT2_SB(sb)     (&((sb)->u.ext2_sb))
-/*
- * Maximal count of links to a file
- */
-#define EXT2_LINK_MAX           32000
-/*
- * Ext2 directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-#define EXT2_FT_UNKNOWN         0
-#define EXT2_FT_REG_FILE        1
-#define EXT2_FT_DIR             2
-#define EXT2_FT_CHRDEV          3
-#define EXT2_FT_BLKDEV          4
-#define EXT2_FT_FIFO            5
-#define EXT2_FT_SOCK            6
-#define EXT2_FT_SYMLINK         7
-
-#define EXT2_FT_MAX             8
-
-#define EXT2_BTREE_FL                   0x00001000 /* btree format dir */
-#define EXT2_RESERVED_FL                0x80000000 /* reserved for ext2 lib */
-#define EXT2_FEATURE_INCOMPAT_FILETYPE          0x0002
-#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                        \
-        ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
-#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                      \
-        ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
-
 /* rw.c */
-int ll_do_writepage(struct page *, int sync);
-int ll_init_pgrqcache(void);
-void ll_cleanup_pgrqcache(void);
-inline void ll_pgrq_del(struct ll_pgrq *pgrq);
-int ll_readpage(struct file *file, struct page *page);
-int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to);
-int ll_commit_write(struct file *file, struct page *page, unsigned from, unsigned to);
-int ll_writepage(struct page *page);
 struct page *ll_getpage(struct inode *inode, unsigned long offset,
                            int create, int locked);
-int ll_write_one_page(struct file *file, struct page *page,
-                         unsigned long offset, unsigned long bytes,
-                         const char * buf);
-int ll_do_vec_wr(struct inode **inodes, obd_count num_io, obd_count num_oa,
-                    struct obdo **obdos, obd_count *oa_bufs,
-                    struct page **pages, char **bufs, obd_size *counts,
-                    obd_off *offsets, obd_flag *flags);
 void ll_truncate(struct inode *inode);
 
-/* super.c */
-extern long ll_cache_count;
-extern long ll_mutex_start;
-
 /* symlink.c */
 extern struct inode_operations ll_fast_symlink_inode_operations;
 extern struct inode_operations ll_symlink_inode_operations;
diff --git a/lustre/lib/page.c b/lustre/lib/page.c
index 50b559bd87..ecd00d37df 100644
--- a/lustre/lib/page.c
+++ b/lustre/lib/page.c
@@ -42,12 +42,8 @@
 
 #define DEBUG_SUBSYSTEM S_OST
 
-#include <linux/obd_support.h>
 #include <linux/obd_class.h>
 #include <linux/lustre_lib.h>
-#include <linux/lustre_idl.h>
-#include <linux/lustre_mds.h>
-#include <linux/lustre_light.h>
 
 /*
  * Remove page from dirty list
diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c
index 2a02a044c9..887cf115f9 100644
--- a/lustre/llite/dir.c
+++ b/lustre/llite/dir.c
@@ -73,6 +73,7 @@ static int ll_dir_readpage(struct file *file, struct page *page)
 	}
 
 	if (Page_Uptodate(page)) {
+                CERROR("Explain this please?\n");
 		EXIT;
 		goto readpage_out;
 	}
@@ -83,11 +84,12 @@ static int ll_dir_readpage(struct file *file, struct page *page)
 			  buf, &request);
 	kunmap(page); 
         ptlrpc_free_req(request);
+        EXIT;
+
+ readpage_out:
         if ( !rc )
                 SetPageUptodate(page);
 
-        EXIT;
- readpage_out:
 	UnlockPage(page);
         return rc;
 } /* ll_dir_readpage */
diff --git a/lustre/llite/file.c b/lustre/llite/file.c
index 0d5bb4fb44..f9bdb92930 100644
--- a/lustre/llite/file.c
+++ b/lustre/llite/file.c
@@ -40,6 +40,7 @@
 #include <linux/lustre_light.h>
 
 extern int ll_setattr(struct dentry *de, struct iattr *attr);
+extern inline struct obdo * ll_oa_from_inode(struct inode *inode, int valid);
 
 static int ll_file_open(struct inode *inode, struct file *file)
 {
@@ -47,7 +48,7 @@ static int ll_file_open(struct inode *inode, struct file *file)
 	int flags = 0; 
 	struct ptlrpc_request *req;
 	struct ll_file_data *fd;
-	struct obdo oa; 
+	struct obdo *oa;
         struct ll_sb_info *sbi = ll_i2sbi(inode);
 	ENTRY;
 
@@ -57,11 +58,11 @@ static int ll_file_open(struct inode *inode, struct file *file)
 		goto out;
 	}
 
-	memset(&oa, 0, sizeof(oa)); 
-	oa.o_valid = OBD_MD_FLMODE | OBD_MD_FLID; 
-	oa.o_mode = inode->i_mode;
-	oa.o_id = HTON__u64((__u64)inode->i_ino);
-	rc = obd_open(ll_i2obdconn(inode),  &oa); 
+        oa = ll_oa_from_inode(inode, (OBD_MD_FLMODE | OBD_MD_FLID));
+        if (oa == NULL)
+                BUG();
+	rc = obd_open(ll_i2obdconn(inode), oa); 
+        obdo_free(oa);
 	if (rc) { 
 		if (rc > 0) 
 			rc = -rc;
@@ -94,7 +95,7 @@ static int ll_file_release(struct inode *inode, struct file *file)
 	int rc;
 	struct ptlrpc_request *req;
 	struct ll_file_data *fd;
-	struct obdo oa; 
+	struct obdo *oa;
         struct ll_sb_info *sbi = ll_i2sbi(inode);
 	ENTRY;
 
@@ -105,11 +106,11 @@ static int ll_file_release(struct inode *inode, struct file *file)
 		goto out;
 	}
 
-	memset(&oa, 0, sizeof(oa)); 
-	oa.o_valid = OBD_MD_FLMODE | OBD_MD_FLID; 
-	oa.o_mode = inode->i_mode;
-	oa.o_id = HTON__u64((__u64)inode->i_ino);
-	rc = obd_close(ll_i2obdconn(inode),  &oa); 
+        oa = ll_oa_from_inode(inode, (OBD_MD_FLMODE | OBD_MD_FLID));
+        if (oa == NULL)
+                BUG();
+	rc = obd_close(ll_i2obdconn(inode), oa); 
+        obdo_free(oa);
 	if (rc) { 
 		if (rc > 0) 
 			rc = -rc;
diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c
index aa33c808c2..0b9ba68bc4 100644
--- a/lustre/llite/namei.c
+++ b/lustre/llite/namei.c
@@ -101,6 +101,7 @@ static struct dentry *ll_lookup(struct inode * dir, struct dentry *dentry)
 			  OBD_MD_FLNOTOBD|OBD_MD_FLBLOCKS, &request);
         if ( err ) {
                 CERROR("obdo_fromid failed\n");
+                ptlrpc_free_req(request);
                 EXIT;
                 return ERR_PTR(-abs(err)); 
         }
@@ -149,7 +150,6 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
      	err = mdc_create(&sbi->ll_mds_client, dir, name, namelen, tgt, tgtlen,
 			 mode, id,  current->uid, current->gid, time, &request);
 	if (err) { 
-                ptlrpc_free_req(request);
                 inode = ERR_PTR(err);
                 EXIT;
                 goto out;
@@ -168,6 +168,7 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
         if (IS_ERR(inode)) {
                 CERROR("new_inode -fatal:  %ld\n", PTR_ERR(inode));
                 inode = ERR_PTR(-EIO);
+                BUG();
                 EXIT;
                 goto out;
         }
@@ -177,6 +178,7 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
 		       rep->ino, atomic_read(&inode->i_count), 
 		       inode->i_nlink);
                 iput(inode);
+                BUG();
                 inode = ERR_PTR(-EIO);
                 EXIT;
                 goto out;
diff --git a/lustre/llite/rw.c b/lustre/llite/rw.c
index 4a2eed27c7..71e78e3f1b 100644
--- a/lustre/llite/rw.c
+++ b/lustre/llite/rw.c
@@ -188,40 +188,43 @@ extern void set_page_clean(struct page *);
 
 
 /* returns the page unlocked, but with a reference */
-int ll_readpage(struct file *file, struct page *page)
+static int ll_readpage(struct file *file, struct page *page)
 {
 	struct inode *inode = page->mapping->host;
-        int rc;
+        int rc = 0;
 
         ENTRY;
 
-	if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT) 
-	     <= page->index) {
+        if (!PageLocked(page))
+                BUG();
+
+	if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT)
+             <= page->index) {
 		memset(kmap(page), 0, PAGE_CACHE_SIZE);
 		kunmap(page);
+                EXIT;
 		goto readpage_out;
 	}
 
 	if (Page_Uptodate(page)) {
+                CERROR("Explain this please?\n");
 		EXIT;
 		goto readpage_out;
 	}
 
         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
-        if ( rc ) {
-		EXIT; 
-		return rc;
-        } 
+        EXIT;
 
  readpage_out:
-	SetPageUptodate(page);
+        if (!rc)
+                SetPageUptodate(page);
 	UnlockPage(page);
-        EXIT;
         return 0;
 } /* ll_readpage */
 
 
-int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int ll_prepare_write(struct file *file, struct page *page, unsigned from,
+                     unsigned to)
 {
         struct inode *inode = page->mapping->host;
         obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
@@ -230,6 +233,9 @@ int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsign
         ENTRY; 
         
 	addr = kmap(page);
+        if (!PageLocked(page))
+                BUG();
+
         if (Page_Uptodate(page)) { 
                 EXIT;
 		goto prepare_done;
@@ -238,40 +244,45 @@ int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsign
         if ( offset + from >= inode->i_size ) {
 		memset(addr, 0, PAGE_SIZE); 
                 EXIT;
-                return 0;
+                goto prepare_done;
         }
         
         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
-        if ( !rc ) {
-                SetPageUptodate(page);
-        } 
 
  prepare_done:
-	set_page_dirty(page);
+        if ( !rc )
+                SetPageUptodate(page);
+
         EXIT;
         return rc;
 }
 
 /* returns the page unlocked, but with a reference */
-int ll_writepage(struct page *page)
+static int ll_writepage(struct page *page)
 {
         struct inode *inode = page->mapping->host;
         int err;
         ENTRY;
 
+        BUG();
+
+        if (!PageLocked(page))
+                BUG();
+
 	err = ll_brw(OBD_BRW_WRITE, inode, page, 1);
         if ( !err ) {
-                SetPageUptodate(page);
+                //SetPageUptodate(page);
 		set_page_clean(page);
 	} else {
 		CERROR("ll_brw failure %d\n", err);
 	}
+        UnlockPage(page); 
         EXIT;
 	return err;
 }
 
 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
-int ll_commit_write(struct file *file, struct page *page, 
+static int ll_commit_write(struct file *file, struct page *page, 
 		    unsigned from, unsigned to)
 {
 	int create = 1;
@@ -291,15 +302,16 @@ int ll_commit_write(struct file *file, struct page *page,
 		return -ENOMEM;
 	}
 
+        if (!PageLocked(page))
+                BUG();
+        if (!Page_Uptodate(page))
+                BUG(); 
+
 	CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n", 
 	       from, to, count);
 
         err = obd_brw(OBD_BRW_WRITE, ll_i2obdconn(inode), num_obdo, &oa,
                       &bufs_per_obdo, &page, &count, &offset, &flags);
-        if ( !err ) {
-                SetPageUptodate(page);
-		set_page_clean(page);
-	}
         kunmap(page);
 
 	if (offset + to > inode->i_size) {
diff --git a/lustre/mds/handler.c b/lustre/mds/handler.c
index 5e5a46a032..5aab7421fa 100644
--- a/lustre/mds/handler.c
+++ b/lustre/mds/handler.c
@@ -123,6 +123,7 @@ struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid,
 			inode->i_nlink, atomic_read(&inode->i_count),
 			inode->i_generation,
 			generation);
+                BUG();
 		iput(inode);
 		return ERR_PTR(-ESTALE);
 	}
@@ -239,8 +240,6 @@ int mds_open(struct ptlrpc_request *req)
 	}		
 	
 	rep->objid = (__u64) (unsigned long)file; 
-	//mds_get_objid(inode, &rep->objid);
-	dput(de); 
 	return 0;
 }
 
@@ -272,6 +271,7 @@ int mds_close(struct ptlrpc_request *req)
 	}
 
         file = (struct file *)(unsigned long) req->rq_req.mds->objid;
+
         req->rq_rephdr->status = filp_close(file, 0); 
 	dput(de); 
 	return 0;
@@ -389,6 +389,16 @@ int mds_handle(struct obd_device *dev, struct ptlrpc_service *svc,
 		rc = mds_reint(req);
 		break;
 
+        case MDS_OPEN:
+                CDEBUG(D_INODE, "open\n");
+                rc = mds_open(req);
+                break;
+
+        case MDS_CLOSE:
+                CDEBUG(D_INODE, "close\n");
+                rc = mds_close(req);
+                break;
+
 	default:
 		return ptlrpc_error(dev, svc, req);
 	}
diff --git a/lustre/mds/mds_reint.c b/lustre/mds/mds_reint.c
index 76523e6670..7bf85eac8d 100644
--- a/lustre/mds/mds_reint.c
+++ b/lustre/mds/mds_reint.c
@@ -102,6 +102,7 @@ static int mds_reint_create(struct mds_update_record *rec,
 	de = mds_fid2dentry(&req->rq_obd->u.mds, rec->ur_fid1, NULL);
 	if (IS_ERR(de)) { 
 		req->rq_rephdr->status = -ESTALE;
+                BUG();
 		EXIT;
 		return 0;
 	}
@@ -113,6 +114,7 @@ static int mds_reint_create(struct mds_update_record *rec,
 		CERROR("child lookup error %d\n", rc);
 		dput(de); 
 		req->rq_rephdr->status = -ESTALE;
+                BUG();
 		EXIT;
 		return 0;
 	}
@@ -122,6 +124,7 @@ static int mds_reint_create(struct mds_update_record *rec,
 		       de->d_inode->i_ino, rec->ur_name);
 		dput(de); 
 		req->rq_rephdr->status = -EEXIST;
+                BUG();
 		EXIT;
 		return 0;
 	}
@@ -129,7 +132,6 @@ static int mds_reint_create(struct mds_update_record *rec,
 	switch (type) {
 	case S_IFREG: { 
 		rc = vfs_create(de->d_inode, dchild, rec->ur_mode);
-		
 		EXIT;
 		break;
 	}
@@ -182,6 +184,7 @@ static int mds_reint_unlink(struct mds_update_record *rec,
 
 	de = mds_fid2dentry(&req->rq_obd->u.mds, rec->ur_fid1, NULL);
 	if (IS_ERR(de)) { 
+                BUG();
 		req->rq_rephdr->status = -ESTALE;
 		EXIT;
 		return 0;
@@ -192,6 +195,7 @@ static int mds_reint_unlink(struct mds_update_record *rec,
 	rc = PTR_ERR(dchild);
 	if (IS_ERR(dchild)) { 
 		CERROR("child lookup error %d\n", rc);
+                BUG();
 		dput(de); 
 		req->rq_rephdr->status = -ESTALE;
 		EXIT;
@@ -201,6 +205,7 @@ static int mds_reint_unlink(struct mds_update_record *rec,
 	if (!dchild->d_inode) {
 		CERROR("child doesn't exist (dir %ld, name %s\n", 
 		       de->d_inode->i_ino, rec->ur_name);
+                BUG();
 		dput(de); 
 		req->rq_rephdr->status = -ESTALE;
 		EXIT;
@@ -244,7 +249,6 @@ static int mds_reint_link(struct mds_update_record *rec,
 
 	de_tgt_dir = mds_fid2dentry(&req->rq_obd->u.mds, rec->ur_fid2, NULL);
 	if (IS_ERR(de_tgt_dir)) { 
-		rc = -ESTALE;
 		EXIT;
 		goto out_link;
 	}
@@ -252,7 +256,7 @@ static int mds_reint_link(struct mds_update_record *rec,
 	dchild = lookup_one_len(rec->ur_name, de_tgt_dir, rec->ur_namelen - 1);
 	if (IS_ERR(dchild)) { 
 		CERROR("child lookup error %d\n", rc);
-		req->rq_rephdr->status = -ESTALE;
+                EXIT;
 		goto out_link;
 	}
 
@@ -264,13 +268,13 @@ static int mds_reint_link(struct mds_update_record *rec,
 	}
 
 	rc = vfs_link(de_src, de_tgt_dir->d_inode, dchild); 
+        EXIT;
 
  out_link:
 	req->rq_rephdr->status = rc;
 	l_dput(de_src);
 	l_dput(de_tgt_dir); 
 	l_dput(dchild); 
-	EXIT;
 	return 0;
 }
 
@@ -294,7 +298,6 @@ static int mds_reint_rename(struct mds_update_record *rec,
 
 	de_tgtdir = mds_fid2dentry(&req->rq_obd->u.mds, rec->ur_fid2, NULL);
 	if (IS_ERR(de_tgtdir)) { 
-		rc = -ESTALE;
 		EXIT;
 		goto out_rename;
 	}
@@ -302,16 +305,19 @@ static int mds_reint_rename(struct mds_update_record *rec,
 	de_old = lookup_one_len(rec->ur_name, de_srcdir, rec->ur_namelen - 1);
 	if (IS_ERR(de_old)) { 
 		CERROR("child lookup error %d\n", rc);
+                EXIT;
 		goto out_rename;
 	}
 
 	de_new = lookup_one_len(rec->ur_tgt, de_tgtdir, rec->ur_tgtlen - 1);
 	if (IS_ERR(de_new)) { 
 		CERROR("child lookup error %d\n", rc);
+                EXIT;
 		goto out_rename;
 	}
 
 	rc = vfs_rename(de_srcdir->d_inode, de_old, de_tgtdir->d_inode, de_new);
+        EXIT;
 
  out_rename:
 	req->rq_rephdr->status = rc;
@@ -319,7 +325,6 @@ static int mds_reint_rename(struct mds_update_record *rec,
 	l_dput(de_old); 
 	l_dput(de_tgtdir); 
 	l_dput(de_srcdir); 
-	EXIT;
 	return 0;
 }
 
@@ -355,8 +360,6 @@ int mds_reint_rec(struct mds_update_record *rec, struct ptlrpc_request *req)
 	req->rq_rephdr->xid = req->rq_reqhdr->xid;
 
 	rc = reinters[rec->ur_opcode](rec, req); 
-	req->rq_status = rc;
-
 	return rc;
 } 
 
diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am
index fb9f04f31c..6995651756 100644
--- a/lustre/tests/Makefile.am
+++ b/lustre/tests/Makefile.am
@@ -2,8 +2,9 @@ CFLAGS:=-g -I. -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I../include -Wal
 KFLAGS:=
 CPPFLAGS :=
 # LDADD := -lreadline -ltermcap # -lefence
-bin_PROGRAMS = testreq truncate
+bin_PROGRAMS = openunlink testreq truncate
 
 testreq_SOURCES = testreq.c
 truncate_SOURCES = truncate.c
+openunlink_SOURCES = openunlink.c
 
diff --git a/lustre/tests/llmount.sh b/lustre/tests/llmount.sh
index 0fcaa83330..30a9286d97 100755
--- a/lustre/tests/llmount.sh
+++ b/lustre/tests/llmount.sh
@@ -20,7 +20,7 @@ mke2fs -b 4096 -F /tmp/ost
 losetup ${LOOP}0 /tmp/ost || exit -1
 
 dd if=/dev/zero of=/tmp/mds bs=1024 count=10000
-mke2fs -b 4096 -F /tmp/mds
+mke2fs -b 4096 -N 150000 -F /tmp/mds
 losetup ${LOOP}1 /tmp/mds || exit -1
 
 mknod /dev/obd c 10 241
diff --git a/lustre/tests/openunlink.c b/lustre/tests/openunlink.c
new file mode 100644
index 0000000000..dddf6a81b2
--- /dev/null
+++ b/lustre/tests/openunlink.c
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h> 
+#include <stdlib.h>
+#include <unistd.h>
+
+#define T1 "write before unlink\n"
+#define T2 "write after unlink\n"
+char buf[128];
+
+int main(int argc, char **argv)
+{
+        int fd, rc;
+
+        if (argc != 2) {
+                fprintf(stderr, "usage: %s filename\n", argv[1]); 
+                exit(1);
+        } else { 
+                fprintf(stderr, "congratulations - program starting\n"); 
+        }
+
+        fprintf(stderr, "opening\n");
+        fd = open(argv[1], O_RDWR | O_TRUNC | O_CREAT, 0644);
+        if (fd == -1) { 
+                fprintf(stderr, "open (before) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "writing\n");
+        rc = write(fd, T1, strlen(T1) + 1); 
+        if (rc != strlen(T1) + 1) { 
+                fprintf(stderr, "write (before) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "closing\n");
+        rc = close(fd); 
+        if (rc )  { 
+                fprintf(stderr, "close (before) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "opening again\n");
+        fd = open(argv[1], O_RDWR );
+        if (fd == -1) { 
+                fprintf(stderr, "open (before) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "unlinking\n");
+        rc = unlink(argv[1]); 
+        if (rc )  { 
+                fprintf(stderr, "open %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "reading\n");
+        rc = read(fd, buf, strlen(T1) + 1); 
+        if (rc != strlen(T1) + 1) { 
+                fprintf(stderr, "read -after %s rc %d\n", strerror(errno), rc); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "comparing data\n");
+        if (memcmp(buf, T1, strlen(T1) + 1) ) { 
+                fprintf(stderr, "FAILURE: read wrong data after unlink\n");
+                exit(1); 
+        }       
+
+        fprintf(stderr, "truncating\n");
+        rc = ftruncate(fd, 0); 
+        if (rc )  { 
+                fprintf(stderr, "truncate -after unl %s\n", strerror(errno)); 
+                exit(1); 
+        }
+        
+        fprintf(stderr, "seeking\n");
+        rc = lseek(fd, 0, SEEK_SET);
+        if (rc != 0 )  { 
+                fprintf(stderr, "seek (before write) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "writing again\n");
+        rc = write(fd, T2, strlen(T2) + 1); 
+        if (rc != strlen(T2) + 1) { 
+                fprintf(stderr, "write (before) %s (rc %d)\n", strerror(errno), rc); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "seeking\n");
+        rc = lseek(fd, 0, SEEK_SET);
+        if (rc != 0 )  { 
+                fprintf(stderr, "seek (before read) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "reading again\n");
+        rc = read(fd, buf, strlen(T2) + 1); 
+        if (rc != strlen(T2) + 1) { 
+                fprintf(stderr, "read (after trunc) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "comparing data again\n");
+        if (memcmp(buf, T2, strlen(T2) + 1) ) { 
+                fprintf(stderr, "FAILURE: read wrong data after trunc\n");
+                exit(1); 
+        }       
+
+        fprintf(stderr, "closing again\n");
+        rc = close(fd); 
+        if (rc )  { 
+                fprintf(stderr, "close (before) %s\n", strerror(errno)); 
+                exit(1); 
+        }
+
+        fprintf(stderr, "SUCCESS - goto beer\n"); 
+        return 0; 
+}
-- 
GitLab