[Ocfs2-commits] mfasheh commits r1484 - branches/dlm-changes/src

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Fri Sep 24 18:15:40 CDT 2004


Author: mfasheh
Date: 2004-09-24 18:15:38 -0500 (Fri, 24 Sep 2004)
New Revision: 1484

Modified:
   branches/dlm-changes/src/dir.c
   branches/dlm-changes/src/dir.h
Log:
* add ocfs_prepare_dir_for_insert - called before a transaction is started,
  this locks a directory for you and makes sure there's a spot large enough
  for the new dirent (including possibly extending the directory).          



Modified: branches/dlm-changes/src/dir.c
===================================================================
--- branches/dlm-changes/src/dir.c	2004-09-24 23:13:26 UTC (rev 1483)
+++ branches/dlm-changes/src/dir.c	2004-09-24 23:15:38 UTC (rev 1484)
@@ -49,10 +49,14 @@
 #include "ocfs_log.h"
 #include "ocfs.h"
 
+#include "alloc.h"
 #include "dir.h"
 #include "dlm.h"
+#include "file.h"
 #include "inode.h"
+#include "ocfs_journal.h"
 #include "namei.h"
+#include "suballoc.h"
 #include "util.h"
 
 #include "buffer_head_io.h"
@@ -63,6 +67,10 @@
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
+static int ocfs_extend_dir(ocfs_super *osb, 
+			   struct inode *dir, 
+			   struct buffer_head *parent_fe_bh,
+			   struct buffer_head **new_de_bh);
 /*
  * ocfs_readdir()
  *
@@ -104,7 +112,7 @@
 
 	while (!error && !stored && filp->f_pos < inode->i_size) {
 		blk = (filp->f_pos) >> sb->s_blocksize_bits;
-		bh = ocfs_bread (NULL, inode, blk, 0, &err, 0);
+		bh = ocfs_bread (inode, blk, &err, 0);
 		if (!bh) {
 			LOG_ERROR_ARGS ("directory #%llu contains a hole at offset %lu\n",
 					OCFS_I(inode)->ip_blkno,
@@ -119,8 +127,9 @@
 		if (!offset) {
 			for (i = 16 >> (sb->s_blocksize_bits - 9), num = 0;
 			     i > 0; i--) {
-				tmp = ocfs_bread (NULL, inode, ++blk, 0, &err, 1);
-				brelse (tmp);
+				tmp = ocfs_bread (inode, ++blk, &err, 1);
+				if (tmp)
+					brelse (tmp);
 			}
 		}
 
@@ -289,7 +298,7 @@
 	sb = inode->i_sb;
 	if ((inode->i_size <
 	     (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) ||
-	    !(bh = ocfs_bread (NULL, inode, 0, 0, &err, 0))) {
+	    !(bh = ocfs_bread (inode, 0, &err, 0))) {
 	    	LOG_ERROR_ARGS ("bad directory (dir #%llu) - no data block\n", 
 				OCFS_I(inode)->ip_blkno);
 		return 1;
@@ -312,8 +321,8 @@
 	while (offset < inode->i_size ) {
 		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 			brelse (bh);
-			bh = ocfs_bread(NULL, inode,
-				      	offset >> sb->s_blocksize_bits, 0, &err, 0);
+			bh = ocfs_bread(inode,
+				      	offset >> sb->s_blocksize_bits, &err, 0);
 			if (!bh) {
 				LOG_ERROR_ARGS ("directory #%llu contains a hole at offset %lu\n",
 					OCFS_I(inode)->ip_blkno, offset);
@@ -337,3 +346,280 @@
 	brelse (bh);
 	return 1;
 }
+
+/* returns a bh of the 1st new block in the allocation. */
+int ocfs_do_extend_dir(struct super_block *sb,
+		       ocfs_journal_handle *handle,
+		       struct inode *dir,
+		       struct buffer_head *parent_fe_bh,
+		       ocfs2_alloc_context *data_ac,
+		       ocfs2_alloc_context *meta_ac,
+		       struct buffer_head **new_bh)
+{
+	int status;
+	s64 vbo, lbo;
+	int extend;
+
+	down(&OCFS_I(dir)->ip_sem);
+	extend = (dir->i_size == OCFS_I(dir)->ip_alloc_size);
+	up(&OCFS_I(dir)->ip_sem);
+
+	if (extend) {
+		status = ocfs_extend_allocation(OCFS_SB(sb), dir, 
+						(1 + (OCFS_I(dir)->ip_alloc_size >> OCFS2_SB(sb)->s_clustersize_bits)), 
+						parent_fe_bh, handle, data_ac, 
+						meta_ac, NULL);
+		OCFS_ASSERT(status != -EAGAIN);
+		if (status < 0) {
+			LOG_ERROR_STATUS(status);
+			goto bail;
+		}
+	}
+
+	vbo = (s64) dir->i_size;
+	lbo = 0;
+
+	status = ocfs_lookup_file_allocation(OCFS_SB(sb), vbo, &lbo, 
+					     sb->s_blocksize, NULL, dir, 1);
+	if (status < 0) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	*new_bh = sb_getblk(sb, lbo >> sb->s_blocksize_bits);
+	if (!*new_bh) {
+		status = -EIO;
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+	status = 0;
+bail:
+	LOG_EXIT_STATUS(status);
+	return(status);
+}
+
+/* assumes you already have a cluster lock on the directory. */
+static int ocfs_extend_dir(ocfs_super *osb, 
+			   struct inode *dir, 
+			   struct buffer_head *parent_fe_bh,
+			   struct buffer_head **new_de_bh)
+{
+	int status = 0;
+	ocfs2_dinode *fe = (ocfs2_dinode *) parent_fe_bh->b_data;
+	int credits, num_free_extents;
+	ocfs2_alloc_context *data_ac = NULL;
+	ocfs2_alloc_context *meta_ac = NULL;
+	ocfs_journal_handle *handle = NULL;
+	struct buffer_head *new_bh = NULL;
+	struct ocfs2_dir_entry * de;
+	struct super_block *sb = osb->sb;
+
+	LOG_ENTRY();
+
+	printk("extending dir %llu (i_size = %llu)\n", OCFS_I(dir)->ip_blkno,
+	       dir->i_size);
+
+	handle = ocfs_alloc_handle(osb);
+	if (handle == NULL) {
+		LOG_ERROR_STATUS (status = -ENOMEM);
+		goto bail;
+	}
+
+	/* dir->i_size is always block aligned. */
+	down(&OCFS_I(dir)->ip_sem);
+	if (dir->i_size == OCFS_I(dir)->ip_alloc_size) {
+		up(&OCFS_I(dir)->ip_sem);
+		num_free_extents = ocfs_num_free_extents(osb, dir, fe);
+		if (num_free_extents < 0) {
+			status = num_free_extents;
+			LOG_ERROR_STATUS(status);
+			goto bail;
+		}
+
+		if (!num_free_extents) {
+			status = ocfs_reserve_new_metadata(osb, handle, dir, 
+							   fe, &meta_ac);
+			if (status < 0) {
+				LOG_ERROR_STATUS (status);
+				goto bail;
+			}
+		}
+
+		status = ocfs_reserve_bits(osb, handle, 1, &data_ac);
+		if (status < 0) {
+			LOG_ERROR_STATUS(status);
+			goto bail;
+		}
+
+		credits = ocfs_calc_extend_credits(sb, 1);
+	} else {
+		up(&OCFS_I(dir)->ip_sem);
+		/* one for the dinode, one for the new block. */
+		credits = 2;
+	}
+
+	handle = ocfs_start_trans(osb, handle, credits);
+	if (handle == NULL) {
+		LOG_ERROR_STATUS(status = -ENOMEM);
+		goto bail;
+	}
+
+	status = ocfs_do_extend_dir(osb->sb, handle, dir, parent_fe_bh, 
+				    data_ac, meta_ac, &new_bh);
+	if (status < 0) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	set_buffer_uptodate(new_bh);
+	SET_BH_SEQNUM(dir, new_bh);
+	status = ocfs_journal_access(handle, new_bh, 
+				     OCFS_JOURNAL_ACCESS_CREATE);
+	if (status < 0) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+	memset(new_bh->b_data, 0, sb->s_blocksize);
+	de = (struct ocfs2_dir_entry *) new_bh->b_data;
+	de->inode = 0;
+	de->rec_len = le16_to_cpu(sb->s_blocksize);
+	status = ocfs_journal_dirty(handle, new_bh);	
+	if (status < 0) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	dir->i_size += dir->i_sb->s_blocksize;
+	dir->i_blocks += 1;
+	status = ocfs_mark_inode_dirty(handle, dir, parent_fe_bh);
+	if (status < 0) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	*new_de_bh = new_bh;
+	get_bh(*new_de_bh);
+bail:
+	if (handle) {
+		if (status < 0)
+			ocfs_abort_trans(handle);
+		else 
+			ocfs_commit_trans(handle);
+	}
+	if (data_ac)
+		ocfs_free_alloc_context(data_ac);
+	if (meta_ac)
+		ocfs_free_alloc_context(meta_ac);
+
+	if ((status < 0) && new_bh)
+		brelse(new_bh);
+
+	LOG_EXIT_STATUS (status);
+	return status;
+}				/* ocfs_extend_dir */
+
+/*
+ * Search the dir for a good spot, extending it if necessary. The
+ * block containing an appropriate record is returned in ret_de_bh.
+ */
+int ocfs_prepare_dir_for_insert(ocfs_super *osb, 
+				struct inode *dir,
+				struct buffer_head *parent_fe_bh,
+				const char *name, 
+				int namelen,
+				struct buffer_head **ret_de_bh)
+{
+	unsigned long offset;
+	struct buffer_head * bh = NULL;
+	unsigned short rec_len;
+	ocfs2_dinode *fe;
+	struct ocfs2_dir_entry * de;
+	struct super_block * sb;
+	int status;
+
+	LOG_ENTRY();
+
+	printk("getting ready to insert namelen %d into dir %llu\n", namelen,
+	       OCFS_I(dir)->ip_blkno);
+
+	OCFS_ASSERT(S_ISDIR(dir->i_mode));
+	fe = (ocfs2_dinode *) parent_fe_bh->b_data;
+	OCFS_ASSERT(fe->i_size == dir->i_size);
+
+	sb = dir->i_sb;
+
+	if (!namelen) {
+		status = -EINVAL;
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	bh = ocfs_bread (dir, 0, &status, 0);
+	if (!bh) {
+		LOG_ERROR_STATUS(status);
+		goto bail;
+	}
+
+	rec_len = OCFS2_DIR_REC_LEN(namelen);
+	offset = 0;
+	de = (struct ocfs2_dir_entry *) bh->b_data;
+	while (1) {
+		if ((char *)de >= sb->s_blocksize + bh->b_data) {
+			brelse (bh);
+			bh = NULL;
+
+			if (dir->i_size <= offset) {
+				status = ocfs_extend_dir(osb, 
+							 dir, 
+							 parent_fe_bh,
+							 &bh);
+				if (status < 0) {
+					LOG_ERROR_STATUS(status);
+					goto bail;
+				}
+				OCFS_ASSERT(bh);
+				*ret_de_bh = bh;
+				get_bh(*ret_de_bh);
+				goto bail;
+			}
+			bh = ocfs_bread (dir, 
+					 offset >> sb->s_blocksize_bits, 
+					 &status, 
+					 0);
+			if (!bh) {
+				LOG_ERROR_STATUS(status);
+				goto bail;
+			}
+			/* move to next block */
+			de = (struct ocfs2_dir_entry *) bh->b_data;
+		}
+		if (!ocfs_check_dir_entry (dir, de, bh, offset)) {
+			status = -ENOENT;
+			goto bail;
+		}
+		if (ocfs_match (namelen, name, de)) {
+			status = -EEXIST;
+			goto bail;
+		}
+		if (((le64_to_cpu(de->inode) == 0) &&
+		     (le16_to_cpu(de->rec_len) >= rec_len)) ||
+		    (le16_to_cpu(de->rec_len) >=
+		     (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
+			/* Ok, we found a spot. Return this bh and let
+			 * the caller actually fill it in. */
+			*ret_de_bh = bh;
+			get_bh(*ret_de_bh);
+			status = 0;
+			goto bail;
+		}
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+
+	status = 0;
+bail:
+	if (bh)
+		brelse(bh);
+	LOG_EXIT_STATUS(status);
+	return(status);
+}

Modified: branches/dlm-changes/src/dir.h
===================================================================
--- branches/dlm-changes/src/dir.h	2004-09-24 23:13:26 UTC (rev 1483)
+++ branches/dlm-changes/src/dir.h	2004-09-24 23:15:38 UTC (rev 1484)
@@ -36,5 +36,17 @@
 			    struct buffer_head **dirent_bh,
 			    struct ocfs2_dir_entry **dirent);
 int ocfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
-
+int ocfs_prepare_dir_for_insert(ocfs_super *osb, 
+				struct inode *dir,
+				struct buffer_head *parent_fe_bh,
+				const char *name, 
+				int namelen,
+				struct buffer_head **ret_de_bh);
+int ocfs_do_extend_dir(struct super_block *sb,
+		       ocfs_journal_handle *handle,
+		       struct inode *dir,
+		       struct buffer_head *parent_fe_bh,
+		       ocfs2_alloc_context *data_ac,
+		       ocfs2_alloc_context *meta_ac,
+		       struct buffer_head **new_bh);
 #endif /* OCFS2_DIR_H */



More information about the Ocfs2-commits mailing list