Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 251713
b: refs/heads/master
c: df5e622
h: refs/heads/master
i:
  251711: 5fae483
v: v3
  • Loading branch information
Jan Kara authored and Theodore Ts'o committed May 3, 2011
1 parent 08a6221 commit 033635f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7ad8e4e6ae2a7c95445ee1715b1714106fb95037
refs/heads/master: df5e6223407e3e645065c4bd968fee007f0e0287
66 changes: 55 additions & 11 deletions trunk/fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2250,17 +2250,34 @@ static int ext4_symlink(struct inode *dir,
handle_t *handle;
struct inode *inode;
int l, err, retries = 0;
int credits;

l = strlen(symname)+1;
if (l > dir->i_sb->s_blocksize)
return -ENAMETOOLONG;

dquot_initialize(dir);

if (l > EXT4_N_BLOCKS * 4) {
/*
* For non-fast symlinks, we just allocate inode and put it on
* orphan list in the first transaction => we need bitmap,
* group descriptor, sb, inode block, quota blocks.
*/
credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
} else {
/*
* Fast symlink. We have to add entry to directory
* (EXT4_DATA_TRANS_BLOCKS + EXT4_INDEX_EXTRA_TRANS_BLOCKS),
* allocate new inode (bitmap, group descriptor, inode block,
* quota blocks, sb is already counted in previous macros).
*/
credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
}
retry:
handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 +
EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
handle = ext4_journal_start(dir, credits);
if (IS_ERR(handle))
return PTR_ERR(handle);

Expand All @@ -2273,21 +2290,44 @@ static int ext4_symlink(struct inode *dir,
if (IS_ERR(inode))
goto out_stop;

if (l > sizeof(EXT4_I(inode)->i_data)) {
if (l > EXT4_N_BLOCKS * 4) {
inode->i_op = &ext4_symlink_inode_operations;
ext4_set_aops(inode);
/*
* page_symlink() calls into ext4_prepare/commit_write.
* We have a transaction open. All is sweetness. It also sets
* i_size in generic_commit_write().
* We cannot call page_symlink() with transaction started
* because it calls into ext4_write_begin() which can wait
* for transaction commit if we are running out of space
* and thus we deadlock. So we have to stop transaction now
* and restart it when symlink contents is written.
*
* To keep fs consistent in case of crash, we have to put inode
* to orphan list in the mean time.
*/
drop_nlink(inode);
err = ext4_orphan_add(handle, inode);
ext4_journal_stop(handle);
if (err)
goto err_drop_inode;
err = __page_symlink(inode, symname, l, 1);
if (err)
goto err_drop_inode;
/*
* Now inode is being linked into dir (EXT4_DATA_TRANS_BLOCKS
* + EXT4_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
*/
handle = ext4_journal_start(dir,
EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 1);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
goto err_drop_inode;
}
inc_nlink(inode);
err = ext4_orphan_del(handle, inode);
if (err) {
ext4_journal_stop(handle);
clear_nlink(inode);
unlock_new_inode(inode);
ext4_mark_inode_dirty(handle, inode);
iput(inode);
goto out_stop;
goto err_drop_inode;
}
} else {
/* clear the extent format for fast symlink */
Expand All @@ -2303,6 +2343,10 @@ static int ext4_symlink(struct inode *dir,
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
err_drop_inode:
unlock_new_inode(inode);
iput(inode);
return err;
}

static int ext4_link(struct dentry *old_dentry,
Expand Down

0 comments on commit 033635f

Please sign in to comment.