- ENTRY;
- sbi = old_dir->i_sb->u.generic_sbp;
-
- new_page = dir_page = NULL;
-
- /* 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
- * and merrily kill the link to whatever was created under the
- * same name. Goodbye sticky bit ;-<
- */
- old_inode = old_dentry->d_inode;
- retval = -ENOENT;
- 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_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) {
- 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_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(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;
- }
- /* 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);
- PDEBUG(new_page, "rename new page");
- if (!new_page)
- goto end_rename;
- }
- new_dir->i_version = ++event;
-
- /*
- * 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;
-
- obdfs_delete_entry (old_de, old_page);
-
- old_dir->i_version = ++event;
- if (new_inode) {
- new_inode->i_nlink--;
- new_inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(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_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) {
- new_inode->i_nlink--;
- mark_inode_dirty(new_inode);
- } else {
- new_dir->i_nlink++;
- new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(new_dir);
- }
- }
- 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);
- }
-#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:
- 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;
+static int obdfs_rename (struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry )
+{
+ struct inode * old_inode = old_dentry->d_inode;
+ struct inode * new_inode = new_dentry->d_inode;
+ struct page * dir_page = NULL;
+ struct ext2_dir_entry_2 * dir_de = NULL;
+ struct page * old_page;
+ struct ext2_dir_entry_2 * old_de;
+ int err = -ENOENT;
+
+ old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
+ if (!old_de)
+ goto out;
+
+ if (S_ISDIR(old_inode->i_mode)) {
+ err = -EIO;
+ dir_de = ext2_dotdot(old_inode, &dir_page);
+ if (!dir_de)
+ goto out_old;
+ }
+
+ if (new_inode) {
+ struct page *new_page;
+ struct ext2_dir_entry_2 *new_de;
+
+ err = -ENOTEMPTY;
+ if (dir_de && !ext2_empty_dir (new_inode))
+ goto out_dir;
+
+ err = -ENOENT;
+ new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
+ if (!new_de)
+ goto out_dir;
+ ext2_inc_count(old_inode);
+ ext2_set_link(new_dir, new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME;
+ if (dir_de)
+ new_inode->i_nlink--;
+ ext2_dec_count(new_inode);
+ } else {
+ if (dir_de) {
+ err = -EMLINK;
+ if (new_dir->i_nlink >= EXT2_LINK_MAX)
+ goto out_dir;
+ }
+ ext2_inc_count(old_inode);
+ err = ext2_add_link(new_dentry, old_inode);
+ if (err) {
+ ext2_dec_count(old_inode);
+ goto out_dir;
+ }
+ if (dir_de)
+ ext2_inc_count(new_dir);
+ }
+
+ ext2_delete_entry (old_de, old_page);
+ ext2_dec_count(old_inode);
+
+ if (dir_de) {
+ ext2_set_link(old_inode, dir_de, dir_page, new_dir);
+ ext2_dec_count(old_dir);
+ }
+ return 0;
+
+
+out_dir:
+ if (dir_de) {
+ kunmap(dir_page);
+ page_cache_release(dir_page);
+ }
+out_old:
+ kunmap(old_page);
+ page_cache_release(old_page);
+out:
+ return err;