}
/*
- * ext2_find_entry()
+ * obdfs_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
static struct page * obdfs_find_entry (struct inode * dir,
- const char * const name, int namelen,
- struct ext2_dir_entry_2 ** res_dir, int lock)
+ const char * const name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int lock)
{
struct super_block * sb;
unsigned long offset;
}
EXIT;
return NULL;
-}
+} /* obdfs_find_entry */
-struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *obdfs_lookup(struct inode *dir, struct dentry *dentry)
{
- struct inode * inode;
- struct ext2_dir_entry_2 * de;
- struct page * page;
+ 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, LOCKED);
+ 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");
d_add(dentry, inode);
EXIT;
return NULL;
-}
+} /* obdfs_lookup */
/*
- * ext2_add_entry()
+ * obdfs_add_entry()
*
* adds a file entry to the specified directory, using the same
* semantics as ext2_find_entry(). It returns NULL if it failed.
* 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
*/
+
+
+/* We do this with a locked page: that's not necessary, since the semaphore
+ * on the inode protects this page as well.
+ */
static struct page *obdfs_add_entry (struct inode * dir,
const char * name, int namelen,
struct ext2_dir_entry_2 ** res_dir,
*/
if (dir->i_size == 0)
{
- EXIT;
+ OIDEBUG(dir);
*err = -ENOENT;
+ EXIT;
return NULL;
}
page = obdfs_getpage(dir, 0, 0, LOCKED);
return NULL;
}
rec_len = EXT2_DIR_REC_LEN(namelen);
- CDEBUG(D_INODE, "reclen: %d\n", rec_len);
+ /* CDEBUG(D_INODE, "reclen: %d\n", rec_len); */
+ PDEBUG(page, "starting search");
offset = 0;
de = (struct ext2_dir_entry_2 *) page_address(page);
*err = -ENOSPC;
while (1) {
- CDEBUG(D_INODE, "Considering entry at %p, (page at %#lx - %#lx), offset %ld\n",
- de, page_address(page), page_address(page) + PAGE_SIZE, offset);
+ /* CDEBUG(D_INODE,
+ "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);
EXIT;
return NULL;
}
+ PDEBUG(page, "new directory page");
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
*err = -ENOENT;
de = (struct ext2_dir_entry_2 *) page_address(page);
}
}
- CDEBUG(D_INODE, "\n");
if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
offset)) {
*err = -ENOENT;
EXIT;
return NULL;
}
- CDEBUG(D_INODE, "Testing for enough space at de %p\n", de);
+ /* 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);
+ /* 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);
+ /*CDEBUG(D_INODE, "Insert 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);
+ /*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);
+ /* 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->i_version = ++event;
*res_dir = de;
*err = 0;
- PDEBUG(page, "addentry");
- CDEBUG(D_INODE, "Regular exit from add_entry");
+ PDEBUG(page, "add_entry");
+ /* XXX unlock page here */
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));
}
- CDEBUG(D_INODE, "\n");
UnlockPage(page);
page_cache_release(page);
- PDEBUG(page, "addentry");
+ PDEBUG(page, "add_entry");
EXIT;
return NULL;
-}
+} /* obdfs_add_entry */
/*
- * ext2_delete_entry deletes a directory entry by merging it with the
+ * obdfs_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
static int obdfs_delete_entry (struct ext2_dir_entry_2 * dir,
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
return -ENOENT;
-}
+} /* obdfs_delete_entry */
static inline void ext2_set_de_type(struct super_block *sb,
dentry->d_name.name, dentry->d_count,
unhashed);
}
-}
+} /* show_dentry */
#endif
+static struct inode *obdfs_new_inode(struct inode *dir, int mode)
+{
+ struct obdo *oa;
+ struct inode *inode;
+ int err;
+
+ ENTRY;
+ oa = obdo_alloc();
+ if (!oa) {
+ EXIT;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Send a hint to the create method on the type of file to create */
+ oa->o_mode = mode;
+ oa->o_valid |= OBD_MD_FLMODE;
+
+ err = IOPS(dir, create)(IID(dir), oa);
+
+ if ( err ) {
+ obdo_free(oa);
+ EXIT;
+ return ERR_PTR(err);
+ }
+
+ inode = iget(dir->i_sb, (ino_t)oa->o_id);
+
+ if (!inode) {
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
+ EXIT;
+ return ERR_PTR(-EIO);
+ }
+
+ if (!list_empty(&inode->i_dentry)) {
+ CDEBUG(D_INODE, "New inode (%ld) has aliases!\n", inode->i_ino);
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
+ iput(inode);
+ EXIT;
+ return ERR_PTR(-EIO);
+ }
+ obdo_free(oa);
+
+ EXIT;
+ return inode;
+} /* obdfs_new_inode */
+
+
/*
* By the time this is called, we already have created
* the directory cache entry for the new file, but it
struct page *page;
struct ext2_dir_entry_2 * de;
int err = -EIO;
- objid id;
ENTRY;
-
- /*
- * N.B. Several error exits in ext2_new_inode don't set err.
- */
- err = iops(dir)->o_create(iid(dir), 0, &id);
- if ( err )
- return err;
- inode = iget(dir->i_sb, (ino_t)id);
- if (!inode || !list_empty(&inode->i_dentry)) {
- CDEBUG(D_INODE, "No inode, ino %ld\n", id);
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
EXIT;
- return -EIO;
+ return PTR_ERR(inode);
}
inode->i_op = &obdfs_file_inode_operations;
- inode->i_mode = mode;
mark_inode_dirty(inode);
page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!page) {
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFREG);
dir->i_version = ++event;
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 0);
+
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
-#if 0
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
-#endif
+
page_cache_release(page);
d_instantiate(dentry, inode);
EXIT;
- return 0;
-}
+ return err;
+} /* obdfs_create */
int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct ext2_dir_entry_2 * de;
int err;
- objid id;
-
ENTRY;
-
- /*
- * N.B. Several error exits in ext2_new_inode don't set err.
- */
- err = iops(dir)->o_create(iid(dir), 0, &id);
- if ( err )
- return err;
- inode = iget(dir->i_sb, (ino_t)id);
- if (!inode)
- return -EIO;
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ return PTR_ERR(inode);
+ }
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
dir->i_version = ++event;
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
mark_inode_dirty(inode);
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 0);
+
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
-#if 0
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
-#endif
d_instantiate(dentry, inode);
page_cache_release(page);
err = 0;
mark_inode_dirty(inode);
iput(inode);
goto out;
-}
+} /* obdfs_mknod */
int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct page *page, *inode_page;
struct ext2_dir_entry_2 * de;
int err;
- objid id;
ENTRY;
if (dir->i_nlink >= EXT2_LINK_MAX)
goto out;
- err = iops(dir)->o_create(iid(dir), 0, &id);
- if ( err )
- return err;
- inode = iget(dir->i_sb, (ino_t)id);
- if (!inode)
- return -EIO;
+ mode |= S_IFDIR;
+ if (dir->i_mode & S_ISGID)
+ mode |= S_ISGID;
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ return PTR_ERR(inode);
+ }
inode->i_op = &obdfs_dir_inode_operations;
inode->i_blocks = 0;
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- iops(dir)->o_brw(WRITE, iid(dir), inode, inode_page, 1);
+ /* XXX handle err */
+ err = obdfs_do_writepage(inode, inode_page, IS_SYNC(inode));
inode->i_blocks = PAGE_SIZE/inode->i_sb->s_blocksize;
inode->i_size = PAGE_SIZE;
UnlockPage(inode_page);
page_cache_release(inode_page);
inode->i_nlink = 2;
- inode->i_mode = S_IFDIR | mode;
- if (dir->i_mode & S_ISGID)
- inode->i_mode |= S_ISGID;
mark_inode_dirty(inode);
/* now deal with the parent */
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
dir->i_version = ++event;
-#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);
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 1);
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
+
UnlockPage(page);
+
page_cache_release(page);
d_instantiate(dentry, inode);
- err = 0;
out:
EXIT;
return err;
iput (inode);
EXIT;
goto out;
-}
+} /* obdfs_mkdir */
/*
UnlockPage(page);
page_cache_release(page);
return 1;
-}
+} /* empty_dir */
int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
struct page *page;
struct ext2_dir_entry_2 * de;
+ int err;
ENTRY;
dir->i_version = ++event;
if (retval)
goto end_rmdir;
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 0);
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
+ /* XXX handle err? */
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)",
page_cache_release(page);
EXIT;
return retval;
-}
+} /* obdfs_rmdir */
int obdfs_unlink(struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
struct page *page;
struct ext2_dir_entry_2 * de;
+ int err;
ENTRY;
if (retval)
goto end_unlink;
dir->i_version = ++event;
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 0);
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
+ /* XXX handle err? */
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);
page_cache_release(page);
EXIT;
return retval;
-}
+} /* obdfs_unlink */
-int obdfs_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 obdfs_inode_info *oinfo;
struct page* page = NULL, * name_page = NULL;
char * link;
int i, l, err = -EIO;
char c;
- objid id;
ENTRY;
- /*
- * N.B. Several error exits in ext2_new_inode don't set err.
- */
- err = iops(dir)->o_create(iid(dir), 0, &id);
- if ( err ) {
+ inode = obdfs_new_inode(dir, S_IFLNK | S_IRWXUGO);
+ if ( IS_ERR(inode) ) {
EXIT;
- return err;
+ return PTR_ERR(inode);
}
- inode = iget(dir->i_sb, (ino_t)id);
- if (!inode) {
- EXIT;
- return err;
- }
- inode->i_mode = S_IFLNK | S_IRWXUGO;
+
inode->i_op = &obdfs_symlink_inode_operations;
- for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
- symname [l]; l++)
+ for (l = 0; l < inode->i_sb->s_blocksize - 1 && symname [l]; l++)
;
- if (l >= sizeof (inode->u.ext2_i.i_data)) {
+ oinfo = obdfs_i2info(inode);
+
+ if (l >= sizeof(oinfo->oi_inline)) {
CDEBUG(D_INODE, "l=%d, normal symlink\n", l);
name_page = obdfs_getpage(inode, 0, 1, LOCKED);
}
link = (char *)page_address(name_page);
} else {
- link = (char *) inode->u.ext2_i.i_data;
+ link = oinfo->oi_inline;
+ oinfo->oi_flags |= OBD_FL_INLINEDATA;
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_page) {
- iops(inode)->o_brw(WRITE, iid(inode), inode, name_page, 1);
+ err = obdfs_do_writepage(inode, name_page, IS_SYNC(inode));
+ /* XXX handle err */
PDEBUG(name_page, "symlink");
UnlockPage(name_page);
page_cache_release(name_page);
inode->i_size = i;
mark_inode_dirty(inode);
- page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ 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;
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 1);
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
-#if 0
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
-#endif
+
d_instantiate(dentry, inode);
- err = 0;
out:
EXIT;
return err;
mark_inode_dirty(inode);
iput (inode);
goto out;
-}
+} /* obdfs_symlink */
int obdfs_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
dir->i_version = ++event;
- iops(dir)->o_brw(WRITE, iid(dir), dir, page, 0);
+
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
-#if 0
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
-#endif
page_cache_release(page);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
inode->i_count++;
d_instantiate(dentry, inode);
- return 0;
-}
+ return err;
+} /* obdfs_link */
#define PARENT_INO(buffer) \
((struct ext2_dir_entry_2 *) ((char *) buffer + \
struct inode * old_inode, * new_inode;
struct page * old_page, * new_page, * dir_page;
struct ext2_dir_entry_2 * old_de, * new_de;
- int retval;
+ int err;
ENTRY;
* same name. Goodbye sticky bit ;-<
*/
old_inode = old_dentry->d_inode;
- retval = -ENOENT;
+ err = -ENOENT;
if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino)
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
/* can only rename into empty new directory */
if (new_inode) {
- retval = -ENOTEMPTY;
+ err = -ENOTEMPTY;
if (!empty_dir (new_inode))
goto end_rename;
}
- retval = -EIO;
+ err = -EIO;
dir_page= obdfs_getpage (old_inode, 0, 0, LOCKED);
PDEBUG(dir_page, "rename dir page");
goto end_rename;
if (le32_to_cpu(PARENT_INO(page_address(dir_page))) != old_dir->i_ino)
goto end_rename;
- retval = -EMLINK;
+ err = -EMLINK;
if (!new_inode && new_dir!=old_dir &&
new_dir->i_nlink >= EXT2_LINK_MAX)
goto end_rename;
if (!new_page) {
new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de,
- &retval);
+ &err);
PDEBUG(new_page, "rename new page");
if (!new_page)
goto end_rename;
old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(old_dir);
if (dir_page) {
- PARENT_INO(page_address(dir_page)) = le32_to_cpu(new_dir->i_ino);
- iops(old_inode)->o_brw(WRITE, iid(old_inode), old_inode, dir_page, 0);
+ PARENT_INO(page_address(dir_page)) =le32_to_cpu(new_dir->i_ino);
+ err = obdfs_do_writepage(old_inode, dir_page,
+ IS_SYNC(old_inode));
+ /* XXX handle err */
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
/* 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, index >> PAGE_SHIFT, 0, LOCKED);
+ old_page = obdfs_getpage(old_dir, index << PAGE_SHIFT, 0,
+ LOCKED);
CDEBUG(D_INODE, "old_page at %p\n", old_page);
- iops(old_dir)->o_brw(WRITE, iid(old_dir), old_dir, old_page,0);
+ err = obdfs_do_writepage(old_dir, old_page, IS_SYNC(old_dir));
+ /* XXX handle err */
}
-#if 0
- if (IS_SYNC(old_dir)) {
- ll_rw_block (WRITE, 1, &old_bh);
- wait_on_buffer (old_bh);
- }
-#endif
- iops(new_dir)->o_brw(WRITE, iid(new_dir), 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;
+ err = obdfs_do_writepage(new_dir, new_page, IS_SYNC(new_dir));
end_rename:
if (old_page && PageLocked(old_page) )
if (dir_page)
page_cache_release(dir_page);
-
- return retval;
-}
+ return err;
+} /* obdfs_rename */