[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