Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 165136
b: refs/heads/master
c: bc13d34
h: refs/heads/master
v: v3
  • Loading branch information
Tao Ma authored and Joel Becker committed Sep 23, 2009
1 parent 76ede06 commit 3ebbc95
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 19bd341f6a6c6b314bcac55bbd906bfd3603fe9e
refs/heads/master: bc13d347574fc0a8a666bc0f4cc2b635d202e372
268 changes: 268 additions & 0 deletions trunk/fs/ocfs2/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2041,6 +2041,274 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
return status;
}

int ocfs2_create_inode_in_orphan(struct inode *dir,
int mode,
struct inode **new_inode)
{
int status, did_quota_inode = 0;
struct inode *inode = NULL;
struct inode *orphan_dir = NULL;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
struct ocfs2_dinode *di = NULL;
handle_t *handle = NULL;
char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
struct buffer_head *parent_di_bh = NULL;
struct buffer_head *new_di_bh = NULL;
struct ocfs2_alloc_context *inode_ac = NULL;
struct ocfs2_dir_lookup_result orphan_insert = { NULL, };

status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
if (status < 0) {
if (status != -ENOENT)
mlog_errno(status);
return status;
}

/*
* We give the orphan dir the root blkno to fake an orphan name,
* and allocate enough space for our insertion.
*/
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
osb->root_blkno,
orphan_name, &orphan_insert);
if (status < 0) {
mlog_errno(status);
goto leave;
}

/* reserve an inode spot */
status = ocfs2_reserve_new_inode(osb, &inode_ac);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
goto leave;
}

inode = ocfs2_get_init_inode(dir, mode);
if (!inode) {
status = -ENOMEM;
mlog_errno(status);
goto leave;
}

handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, 0, 0));
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
handle = NULL;
mlog_errno(status);
goto leave;
}

/* We don't use standard VFS wrapper because we don't want vfs_dq_init
* to be called. */
if (sb_any_quota_active(osb->sb) &&
osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) {
status = -EDQUOT;
goto leave;
}
did_quota_inode = 1;

/* do the real work now. */
status = ocfs2_mknod_locked(osb, dir, inode,
0, &new_di_bh, parent_di_bh, handle,
inode_ac);
if (status < 0) {
mlog_errno(status);
goto leave;
}

status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name);
if (status < 0) {
mlog_errno(status);
goto leave;
}

di = (struct ocfs2_dinode *)new_di_bh->b_data;
status = ocfs2_orphan_add(osb, handle, inode, di, orphan_name,
&orphan_insert, orphan_dir);
if (status < 0) {
mlog_errno(status);
goto leave;
}

/* get open lock so that only nodes can't remove it from orphan dir. */
status = ocfs2_open_lock(inode);
if (status < 0)
mlog_errno(status);

leave:
if (status < 0 && did_quota_inode)
vfs_dq_free_inode(inode);
if (handle)
ocfs2_commit_trans(osb, handle);

if (orphan_dir) {
/* This was locked for us in ocfs2_prepare_orphan_dir() */
ocfs2_inode_unlock(orphan_dir, 1);
mutex_unlock(&orphan_dir->i_mutex);
iput(orphan_dir);
}

if (status == -ENOSPC)
mlog(0, "Disk is full\n");

if ((status < 0) && inode) {
clear_nlink(inode);
iput(inode);
}

if (inode_ac)
ocfs2_free_alloc_context(inode_ac);

brelse(new_di_bh);

if (!status)
*new_inode = inode;

ocfs2_free_dir_lookup_result(&orphan_insert);

ocfs2_inode_unlock(dir, 1);
brelse(parent_di_bh);
return status;
}

int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
struct inode *inode,
struct dentry *dentry)
{
int status = 0;
struct buffer_head *parent_di_bh = NULL;
handle_t *handle = NULL;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
struct ocfs2_dinode *dir_di, *di;
struct inode *orphan_dir_inode = NULL;
struct buffer_head *orphan_dir_bh = NULL;
struct buffer_head *di_bh = NULL;
struct ocfs2_dir_lookup_result lookup = { NULL, };

mlog_entry("(0x%p, 0x%p, %.*s')\n", dir, dentry,
dentry->d_name.len, dentry->d_name.name);

status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
if (status < 0) {
if (status != -ENOENT)
mlog_errno(status);
return status;
}

dir_di = (struct ocfs2_dinode *) parent_di_bh->b_data;
if (!dir_di->i_links_count) {
/* can't make a file in a deleted directory. */
status = -ENOENT;
goto leave;
}

status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
dentry->d_name.len);
if (status)
goto leave;

/* get a spot inside the dir. */
status = ocfs2_prepare_dir_for_insert(osb, dir, parent_di_bh,
dentry->d_name.name,
dentry->d_name.len, &lookup);
if (status < 0) {
mlog_errno(status);
goto leave;
}

orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
osb->slot_num);
if (!orphan_dir_inode) {
status = -EEXIST;
mlog_errno(status);
goto leave;
}

mutex_lock(&orphan_dir_inode->i_mutex);

status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
if (status < 0) {
mlog_errno(status);
mutex_unlock(&orphan_dir_inode->i_mutex);
iput(orphan_dir_inode);
goto leave;
}

status = ocfs2_read_inode_block(inode, &di_bh);
if (status < 0) {
mlog_errno(status);
goto orphan_unlock;
}

handle = ocfs2_start_trans(osb, ocfs2_rename_credits(osb->sb));
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
handle = NULL;
mlog_errno(status);
goto orphan_unlock;
}

status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
di_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
goto out_commit;
}

status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
orphan_dir_bh);
if (status < 0) {
mlog_errno(status);
goto out_commit;
}

di = (struct ocfs2_dinode *)di_bh->b_data;
le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
di->i_orphaned_slot = 0;
ocfs2_journal_dirty(handle, di_bh);

status = ocfs2_add_entry(handle, dentry, inode,
OCFS2_I(inode)->ip_blkno, parent_di_bh,
&lookup);
if (status < 0) {
mlog_errno(status);
goto out_commit;
}

status = ocfs2_dentry_attach_lock(dentry, inode,
OCFS2_I(dir)->ip_blkno);
if (status) {
mlog_errno(status);
goto out_commit;
}

insert_inode_hash(inode);
dentry->d_op = &ocfs2_dentry_ops;
d_instantiate(dentry, inode);
status = 0;
out_commit:
ocfs2_commit_trans(osb, handle);
orphan_unlock:
ocfs2_inode_unlock(orphan_dir_inode, 1);
mutex_unlock(&orphan_dir_inode->i_mutex);
iput(orphan_dir_inode);
leave:

ocfs2_inode_unlock(dir, 1);

brelse(di_bh);
brelse(parent_di_bh);
brelse(orphan_dir_bh);

ocfs2_free_dir_lookup_result(&lookup);

mlog_exit(status);

return status;
}

const struct inode_operations ocfs2_dir_iops = {
.create = ocfs2_create,
.lookup = ocfs2_lookup,
Expand Down
6 changes: 6 additions & 0 deletions trunk/fs/ocfs2/namei.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,11 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
struct inode *orphan_dir_inode,
struct inode *inode,
struct buffer_head *orphan_dir_bh);
int ocfs2_create_inode_in_orphan(struct inode *dir,
int mode,
struct inode **new_inode);
int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
struct inode *new_inode,
struct dentry *new_dentry);

#endif /* OCFS2_NAMEI_H */

0 comments on commit 3ebbc95

Please sign in to comment.