#include <linux/locks.h>
#include <linux/quotaops.h>
#include <linux/iobuf.h>
+
+#include <linux/obd_support.h>
#include "obdfs.h"
/*
*/
struct page * obdfs_find_entry (struct inode * dir,
const char * const name, int namelen,
- struct ext2_dir_entry_2 ** res_dir)
+ struct ext2_dir_entry_2 ** res_dir, int lock)
{
struct super_block * sb;
unsigned long offset;
struct page * page;
+ ENTRY;
+ CDEBUG(D_INODE, "find entry for %*s\n", namelen, name);
*res_dir = NULL;
sb = dir->i_sb;
if (namelen > EXT2_NAME_LEN)
return NULL;
- for (page = 0, offset = 0; offset < dir->i_size; page++) {
+ CDEBUG(D_INODE, "dirsize is %ld\n", dir->i_size);
+
+ page = 0;
+ offset = 0;
+ while ( offset < dir->i_size ) {
struct ext2_dir_entry_2 * de;
char * dlimit;
- page = obdfs_getpage(dir, offset);
+ page = obdfs_getpage(dir, offset, 0, lock);
+
+ if ( !page ) {
+ CDEBUG(D_INODE, "No page, offset %lx\n", offset);
+ return NULL;
+ }
de = (struct ext2_dir_entry_2 *) page_address(page);
dlimit = (char *)page_address(page) + PAGE_SIZE;
/* this code is executed quadratically often */
/* do minimal checking `by hand' */
int de_len;
+ CDEBUG(D_INODE, "Entry %p len %d, page at %#lx - %#lx , offset %lx\n",
+ de, le16_to_cpu(de->rec_len), page_address(page), page_address(page) +
+ PAGE_SIZE, offset);
if ((char *) de + namelen <= dlimit &&
ext2_match (namelen, name, de)) {
/* found a match -
just to be sure, do a full check */
-#if 0
- if (!ext2_check_dir_entry("ext2_find_entry",
- dir, de, bh, offset))
+ if (!obdfs_check_dir_entry("ext2_find_entry",
+ dir, de, page, offset))
goto failure;
-#endif
*res_dir = de;
+ EXIT;
return page;
}
/* prevent looping on a bad block */
de_len = le16_to_cpu(de->rec_len);
- if (de_len <= 0)
+ if (de_len <= 0) {
+ CDEBUG(D_INODE, "Bad entry: at %p len %d\n",
+ de, de_len);
goto failure;
+ }
offset += de_len;
de = (struct ext2_dir_entry_2 *)
((char *) de + de_len);
+ CDEBUG(D_INODE, "Next while %lx\n", offset);
}
+ if ( lock )
+ UnlockPage(page);
page_cache_release(page);
+ page = NULL;
+ CDEBUG(D_INODE, "Next for %lx\n", offset);
}
failure:
+ CDEBUG(D_INODE, "Negative case, page %p, offset %ld\n", page, offset);
+ if (page) {
+ if (lock)
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+ EXIT;
return NULL;
}
struct inode * inode;
struct ext2_dir_entry_2 * de;
struct page * page;
+ ENTRY;
if (dentry->d_name.len > EXT2_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
inode = NULL;
+ if ( !page )
+ CDEBUG(D_INODE, "No page - negative entry.\n");
+ if ( page && !de ) {
+ CDEBUG(D_INODE, "Danger: PAGE but de.\n");
+ return ERR_PTR(-ENOENT);
+ }
if (page) {
unsigned long ino = le32_to_cpu(de->inode);
+ UnlockPage(page);
page_cache_release(page);
inode = iget(dir->i_sb, ino);
- if (!inode)
+ if (!inode) {
+ CDEBUG(D_INODE, "No inode.\n");
+ EXIT;
return ERR_PTR(-EACCES);
+ }
}
d_add(dentry, inode);
+ EXIT;
return NULL;
}
-#if 0
/*
* ext2_add_entry()
*
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
+
+ * returns a locked and held page upon success
*/
-static struct buffer_head * ext2_add_entry (struct inode * dir,
- const char * name, int namelen,
- struct ext2_dir_entry_2 ** res_dir,
- int *err)
+static struct page *obdfs_add_entry (struct inode * dir,
+ const char * name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int *err)
{
unsigned long offset;
unsigned short rec_len;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
+ ENTRY;
*err = -EINVAL;
*res_dir = NULL;
- if (!dir || !dir->i_nlink)
+ if (!dir || !dir->i_nlink) {
+ EXIT;
return NULL;
+ }
sb = dir->i_sb;
- if (!namelen)
+ if (!namelen) {
+ EXIT;
return NULL;
+ }
/*
* Is this a busy deleted directory? Can't create new files if so
*/
if (dir->i_size == 0)
{
+ EXIT;
*err = -ENOENT;
return NULL;
}
- bh = ext2_bread (dir, 0, 0, err);
- if (!bh)
+ page = obdfs_getpage(dir, 0, 0, LOCKED);
+ if (!page) {
+ EXIT;
return NULL;
+ }
rec_len = EXT2_DIR_REC_LEN(namelen);
+ CDEBUG(D_INODE, "reclen: %d\n", rec_len);
offset = 0;
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
*err = -ENOSPC;
while (1) {
- if ((char *)de >= sb->s_blocksize + bh->b_data) {
- brelse (bh);
- bh = NULL;
- bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);
- if (!bh)
+ CDEBUG(D_INODE, "Considering entry at %p, (page at %#lx - %#lx), offset %ld\n",
+ de, page_address(page), page_address(page) + PAGE_SIZE, offset);
+ if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
+ UnlockPage(page);
+ page_cache_release(page);
+ page = obdfs_getpage(dir, offset, 1, LOCKED);
+ if (!page) {
+ EXIT;
return NULL;
+ }
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
*err = -ENOENT;
+ EXIT;
return NULL;
}
- ext2_debug ("creating next block\n");
+ CDEBUG(D_INODE, "creating next block\n");
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
de->inode = 0;
- de->rec_len = le16_to_cpu(sb->s_blocksize);
- dir->i_size = offset + sb->s_blocksize;
+ de->rec_len = le16_to_cpu(PAGE_SIZE);
+ dir->i_size = offset + PAGE_SIZE;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
} else {
ext2_debug ("skipping to next block\n");
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
}
}
- if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
+ CDEBUG(D_INODE, "\n");
+ if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
offset)) {
*err = -ENOENT;
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
+ EXIT;
return NULL;
}
+ CDEBUG(D_INODE, "\n");
if (ext2_match (namelen, name, de)) {
*err = -EEXIST;
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
+ EXIT;
return NULL;
}
- if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
- (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
+ CDEBUG(D_INODE, "Testing for enough space at de %p\n", de);
+ if ( (le32_to_cpu(de->inode) == 0 &&
+ le16_to_cpu(de->rec_len) >= rec_len) ||
+ (le16_to_cpu(de->rec_len) >=
+ EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
offset += le16_to_cpu(de->rec_len);
+ CDEBUG(D_INODE, "Found enough space de %p, offset %#lx\n", de, offset);
if (le32_to_cpu(de->inode)) {
+ CDEBUG(D_INODE, "Inserting new in %p\n", de);
de1 = (struct ext2_dir_entry_2 *) ((char *) de +
EXT2_DIR_REC_LEN(de->name_len));
+ CDEBUG(D_INODE, "-- de1 at %p\n", de1);
de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
EXT2_DIR_REC_LEN(de->name_len));
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
de = de1;
}
+ CDEBUG(D_INODE, "Reclen adjusted; copy %d bytes to %p, page at %#lx EOP at %#lx\n", namelen, de->name, page_address(page), page_address(page) + PAGE_SIZE);
de->inode = 0;
de->name_len = namelen;
de->file_type = 0;
memcpy (de->name, name, namelen);
+ CDEBUG(D_INODE, "Copy done\n");
/*
* XXX shouldn't update any times until successful
* completion of syscall, but too many callers depend
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
*res_dir = de;
*err = 0;
- return bh;
+ PDEBUG(page, "addentry");
+ CDEBUG(D_INODE, "Regular exit from add_entry");
+ EXIT;
+ return page;
}
+ CDEBUG(D_INODE, "\n");
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+
}
- brelse (bh);
+ CDEBUG(D_INODE, "\n");
+
+ UnlockPage(page);
+ page_cache_release(page);
+ PDEBUG(page, "addentry");
+ EXIT;
return NULL;
}
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
- struct buffer_head * bh)
+static int obdfs_delete_entry (struct ext2_dir_entry_2 * dir,
+ struct page * page)
{
struct ext2_dir_entry_2 * de, * pde;
int i;
i = 0;
pde = NULL;
- de = (struct ext2_dir_entry_2 *) bh->b_data;
- while (i < bh->b_size) {
- if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
- de, bh, i))
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ while (i < PAGE_SIZE) {
+ if (!obdfs_check_dir_entry ("ext2_delete_entry", NULL,
+ de, page, i))
return -EIO;
if (de == dir) {
if (pde)
return -ENOENT;
}
+
static inline void ext2_set_de_type(struct super_block *sb,
struct ext2_dir_entry_2 *de,
umode_t mode) {
de->file_type = EXT2_FT_DIR;
}
+
+/*
+ * Display all dentries holding the specified inode.
+ */
+static void show_dentry(struct list_head * dlist, int subdirs)
+{
+ struct list_head *tmp = dlist;
+
+ while ((tmp = tmp->next) != dlist) {
+ struct dentry * dentry;
+ const char * unhashed = "";
+
+ if ( subdirs )
+ dentry = list_entry(tmp, struct dentry, d_child);
+ else
+ dentry = list_entry(tmp, struct dentry, d_alias);
+
+ if (list_empty(&dentry->d_hash))
+ unhashed = "(unhashed)";
+
+ if ( dentry->d_inode )
+ printk("show_dentry: %s/%s, d_count=%d%s (ino %ld, dev %d, ct %d)\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, dentry->d_count,
+ unhashed, dentry->d_inode->i_ino,
+ dentry->d_inode->i_dev,
+ dentry->d_inode->i_count);
+ else
+ printk("show_dentry: %s/%s, d_count=%d%s \n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, dentry->d_count,
+ unhashed);
+ }
+}
+
+
/*
* By the time this is called, we already have created
* the directory cache entry for the new file, but it
* If the create succeeds, we fill in the inode information
* with d_instantiate().
*/
-int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
+int obdfs_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
int err = -EIO;
+ struct obdfs_sb_info *sbi;
+ ino_t ino;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
- inode = ext2_new_inode (dir, mode, &err);
- if (!inode)
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
+ if ( err )
+ return err;
+ err = -EIO;
+ inode = iget(dir->i_sb, ino);
+ if (!inode || !list_empty(&inode->i_dentry)) {
+ CDEBUG(D_INODE, "No inode, ino %ld\n", ino);
+ EXIT;
return err;
+ }
- inode->i_op = &ext2_file_inode_operations;
+ inode->i_op = &obdfs_inode_ops;
inode->i_mode = mode;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
+ EXIT;
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFREG);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
+ page_cache_release(page);
d_instantiate(dentry, inode);
+ EXIT;
return 0;
}
-int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
int err = -EIO;
+ struct obdfs_sb_info *sbi;
+
+ ino_t ino;
- inode = ext2_new_inode (dir, mode, &err);
+ ENTRY;
+
+ sbi = dir->i_sb->u.generic_sbp;
+ /*
+ * N.B. Several error exits in ext2_new_inode don't set err.
+ */
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ inode = iget(dir->i_sb, ino);
if (!inode)
- goto out;
+ return err;
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
mark_inode_dirty(inode);
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir, page, 0);
+ UnlockPage(page);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
d_instantiate(dentry, inode);
- brelse(bh);
+ page_cache_release(page);
err = 0;
out:
return err;
goto out;
}
-int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- struct buffer_head * bh, * dir_block;
+ struct inode * child;
+ struct page *page, *child_page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
int err;
+ ino_t ino;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
err = -EMLINK;
if (dir->i_nlink >= EXT2_LINK_MAX)
goto out;
err = -EIO;
- inode = ext2_new_inode (dir, S_IFDIR, &err);
- if (!inode)
- goto out;
+ ino = iops(dir)->o_create(sbi->osi_conn_info.conn_id, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ child = iget(dir->i_sb, ino);
+ if (!child)
+ return err;
- inode->i_op = &ext2_dir_inode_operations;
- inode->i_size = inode->i_sb->s_blocksize;
- inode->i_blocks = 0;
- dir_block = ext2_bread (inode, 0, 1, &err);
- if (!dir_block) {
- inode->i_nlink--; /* is this nlink == 0? */
- mark_inode_dirty(inode);
- iput (inode);
+
+ child->i_op = &obdfs_inode_ops;
+ child->i_size = PAGE_SIZE;
+ child->i_blocks = 0;
+ child_page = obdfs_getpage(child, 0, 1, LOCKED);
+ if (!child_page) {
+ child->i_nlink--; /* is this nlink == 0? */
+ mark_inode_dirty(child);
+ iput (child);
return err;
}
- de = (struct ext2_dir_entry_2 *) dir_block->b_data;
- de->inode = cpu_to_le32(inode->i_ino);
+ child->i_blocks = PAGE_SIZE/child->i_sb->s_blocksize;
+
+ /* create . and .. */
+ de = (struct ext2_dir_entry_2 *) page_address(child_page);
+ de->inode = cpu_to_le32(child->i_ino);
de->name_len = 1;
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
strcpy (de->name, ".");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
+
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
de->inode = cpu_to_le32(dir->i_ino);
- de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
+ de->rec_len = cpu_to_le16(PAGE_SIZE - EXT2_DIR_REC_LEN(1));
de->name_len = 2;
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
- brelse (dir_block);
- inode->i_mode = S_IFDIR | mode;
+
+ iops(dir)->o_brw(WRITE, sbi->osi_conn_info.conn_id, child, child_page, 1);
+ UnlockPage(child_page);
+ page_cache_release(child_page);
+
+ child->i_nlink = 2;
+ child->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
- inode->i_mode |= S_ISGID;
- mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ child->i_mode |= S_ISGID;
+ mark_inode_dirty(child);
+
+ /* now deal with the parent */
+ page = obdfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
+ }
+
+ de->inode = cpu_to_le32(child->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
dir->i_nlink++;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
- d_instantiate(dentry, inode);
- brelse (bh);
+ iops(dir)->o_brw(WRITE, sbi->osi_conn_info.conn_id, dir, page, 1);
+ UnlockPage(page);
+ page_cache_release(page);
+ d_instantiate(dentry, child);
err = 0;
out:
+ EXIT;
return err;
out_no_entry:
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput (inode);
+ child->i_nlink = 0;
+ mark_inode_dirty(child);
+ iput (child);
+ EXIT;
goto out;
}
+
/*
* routine to check that the specified directory is empty (for rmdir)
*/
static int empty_dir (struct inode * inode)
{
unsigned long offset;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
- int err;
sb = inode->i_sb;
if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
- !(bh = ext2_bread (inode, 0, 0, &err))) {
+ !(page = obdfs_getpage (inode, 0, 0, LOCKED))) {
ext2_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no data block",
inode->i_ino);
return 1;
}
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) ||
strcmp (".", de->name) || strcmp ("..", de1->name)) {
ext2_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no `.' or `..'",
inode->i_ino);
- brelse (bh);
+ page_cache_release(page);
return 1;
}
offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
while (offset < inode->i_size ) {
- if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
- brelse (bh);
- bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
- if (!bh) {
+ if (!page || (void *) de >= (void *) (page_address(page) + PAGE_SIZE)) {
+ if (page) {
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+ page = obdfs_getpage(inode, offset, 0, LOCKED);
+ if (!page) {
#if 0
ext2_error (sb, "empty_dir",
"directory #%lu contains a hole at offset %lu",
offset += sb->s_blocksize;
continue;
}
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
}
- if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
+ if (!obdfs_check_dir_entry ("empty_dir", inode, de, page,
offset)) {
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
return 1;
}
if (le32_to_cpu(de->inode)) {
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
return 0;
}
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
return 1;
}
-int ext2_rmdir (struct inode * dir, struct dentry *dentry)
+int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
- if (!bh)
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
+ if (!page)
goto end_rmdir;
inode = dentry->d_inode;
if (!empty_dir (inode))
goto end_rmdir;
- retval = ext2_delete_entry (de, bh);
+ retval = obdfs_delete_entry (de, page);
dir->i_version = ++event;
if (retval)
goto end_rmdir;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id, dir, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
if (inode->i_nlink != 2)
ext2_warning (inode->i_sb, "ext2_rmdir",
"empty directory has nlink!=2 (%d)",
d_delete(dentry);
end_rmdir:
- brelse (bh);
+ if ( page )
+ page_cache_release(page);
+ EXIT;
return retval;
}
-int ext2_unlink(struct inode * dir, struct dentry *dentry)
+int obdfs_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
- if (!bh)
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
+ if (!page)
goto end_unlink;
inode = dentry->d_inode;
inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
- retval = ext2_delete_entry (de, bh);
+ retval = obdfs_delete_entry (de, page);
if (retval)
goto end_unlink;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id, dir, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
d_delete(dentry); /* This also frees the inode */
end_unlink:
- brelse (bh);
+ if (page)
+ page_cache_release(page);
+ EXIT;
return retval;
}
-int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
+int obdfs_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct ext2_dir_entry_2 * de;
struct inode * inode;
- struct buffer_head * bh = NULL, * name_block = NULL;
+ struct page* page = NULL, * name_page = NULL;
char * link;
int i, l, err = -EIO;
char c;
+ struct obdfs_sb_info *sbi;
+ ino_t ino;
+
+ ENTRY;
- if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) {
+ sbi = dir->i_sb->u.generic_sbp;
+ /*
+ * N.B. Several error exits in ext2_new_inode don't set err.
+ */
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
return err;
- }
+
inode->i_mode = S_IFLNK | S_IRWXUGO;
- inode->i_op = &ext2_symlink_inode_operations;
+ inode->i_op = &obdfs_inode_ops;
for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
symname [l]; l++)
;
if (l >= sizeof (inode->u.ext2_i.i_data)) {
- ext2_debug ("l=%d, normal symlink\n", l);
+ CDEBUG(D_INODE, "l=%d, normal symlink\n", l);
- name_block = ext2_bread (inode, 0, 1, &err);
- if (!name_block) {
+ name_page = obdfs_getpage(inode, 0, 1, LOCKED);
+ if (!name_page) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
return err;
}
- link = name_block->b_data;
+ link = (char *)page_address(name_page);
} else {
link = (char *) inode->u.ext2_i.i_data;
- ext2_debug ("l=%d, fast symlink\n", l);
+ CDEBUG(D_INODE, "l=%d, fast symlink\n", l);
}
i = 0;
while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++)))
link[i++] = c;
link[i] = 0;
- if (name_block) {
- mark_buffer_dirty(name_block, 1);
- brelse (name_block);
+ if (name_page) {
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ inode, name_page, 1);
+ PDEBUG(name_page, "symlink");
+ UnlockPage(name_page);
+ page_cache_release(name_page);
}
inode->i_size = i;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFLNK);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir, page, 1);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
d_instantiate(dentry, inode);
err = 0;
out:
goto out;
}
-int ext2_link (struct dentry * old_dentry,
+int obdfs_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
struct ext2_dir_entry_2 * de;
- struct buffer_head * bh;
+ struct page *page;
int err;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
if (S_ISDIR(inode->i_mode))
return -EPERM;
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
return err;
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir, page, 0);
+ UnlockPage(page);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
+ page_cache_release(page);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir,struct dentry *new_dentry)
+int obdfs_rename (struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
- struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct page * old_page, * new_page, * dir_page;
struct ext2_dir_entry_2 * old_de, * new_de;
int retval;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = old_dir->i_sb->u.generic_sbp;
- old_bh = new_bh = dir_bh = NULL;
+ new_page = dir_page = NULL;
- old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+ /* does the old entry exist? - if not get out */
+ old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de, NOLOCK);
+ PDEBUG(old_page, "rename - old page");
/*
* Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process
*/
old_inode = old_dentry->d_inode;
retval = -ENOENT;
- if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
+ if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino)
goto end_rename;
+ /* find new inode */
new_inode = new_dentry->d_inode;
- new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len, &new_de);
- if (new_bh) {
+ new_page = obdfs_find_entry (new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de, NOLOCK);
+ PDEBUG(new_page, "rename - new page ");
+ if (new_page) {
if (!new_inode) {
- brelse (new_bh);
- new_bh = NULL;
+ page_cache_release(new_page);
+ new_page = NULL;
} else {
DQUOT_INIT(new_inode);
}
}
+ /* in this case we to check more ... */
if (S_ISDIR(old_inode->i_mode)) {
+ /* can only rename into empty new directory */
if (new_inode) {
retval = -ENOTEMPTY;
if (!empty_dir (new_inode))
goto end_rename;
}
retval = -EIO;
- dir_bh = ext2_bread (old_inode, 0, 0, &retval);
- if (!dir_bh)
+ dir_page= obdfs_getpage (old_inode, 0, 0, LOCKED);
+ PDEBUG(dir_page, "rename dir page");
+
+ if (!dir_page)
goto end_rename;
- if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+ if (le32_to_cpu(PARENT_INO(page_address(dir_page))) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
if (!new_inode && new_dir!=old_dir &&
new_dir->i_nlink >= EXT2_LINK_MAX)
goto end_rename;
}
- if (!new_bh) {
- new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name,
+ /* create the target dir entry */
+ if (!new_page) {
+ new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de,
&retval);
- if (!new_bh)
+ PDEBUG(new_page, "rename new page");
+ if (!new_page)
goto end_rename;
}
new_dir->i_version = ++event;
/*
- * ok, that's it
+ * remove the old entry
*/
new_de->inode = le32_to_cpu(old_inode->i_ino);
if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
EXT2_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
- ext2_delete_entry (old_de, old_bh);
+ obdfs_delete_entry (old_de, old_page);
old_dir->i_version = ++event;
if (new_inode) {
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(old_dir);
- if (dir_bh) {
- PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh, 1);
+ if (dir_page) {
+ PARENT_INO(page_address(dir_page)) = le32_to_cpu(new_dir->i_ino);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ old_inode, dir_page, 0);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
mark_inode_dirty(new_dir);
}
}
- mark_buffer_dirty(old_bh, 1);
+ if ( old_page != new_page ) {
+ unsigned long offset = old_page->offset;
+ /* lock the old_page and release unlocked copy */
+ CDEBUG(D_INODE, "old_page at %p\n", old_page);
+ page_cache_release(old_page);
+ old_page = obdfs_getpage(old_dir, offset, 0, LOCKED);
+ CDEBUG(D_INODE, "old_page at %p\n", old_page);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ old_dir, old_page, 0);
+ }
+#if 0
if (IS_SYNC(old_dir)) {
ll_rw_block (WRITE, 1, &old_bh);
wait_on_buffer (old_bh);
}
- mark_buffer_dirty(new_bh, 1);
+#endif
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ new_dir, new_page, 0);
+#if 0
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
}
+#endif
retval = 0;
end_rename:
- brelse (dir_bh);
- brelse (old_bh);
- brelse (new_bh);
+ if (old_page && PageLocked(old_page) )
+ UnlockPage(old_page);
+ if (old_page)
+ page_cache_release(old_page);
+ if (new_page && PageLocked(new_page) )
+ UnlockPage(new_page);
+ if (new_page)
+ page_cache_release(new_page);
+ if (dir_page && PageLocked(dir_page) )
+ UnlockPage(dir_page);
+ if (dir_page)
+ page_cache_release(dir_page);
+
+
return retval;
}
-#endif