mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (25 commits) cifs: remove unnecessary dentry_unhash on rmdir/rename_dir ocfs2: remove unnecessary dentry_unhash on rmdir/rename_dir exofs: remove unnecessary dentry_unhash on rmdir/rename_dir nfs: remove unnecessary dentry_unhash on rmdir/rename_dir ext2: remove unnecessary dentry_unhash on rmdir/rename_dir ext3: remove unnecessary dentry_unhash on rmdir/rename_dir ext4: remove unnecessary dentry_unhash on rmdir/rename_dir btrfs: remove unnecessary dentry_unhash in rmdir/rename_dir ceph: remove unnecessary dentry_unhash calls vfs: clean up vfs_rename_other vfs: clean up vfs_rename_dir vfs: clean up vfs_rmdir vfs: fix vfs_rename_dir for FS_RENAME_DOES_D_MOVE filesystems libfs: drop unneeded dentry_unhash vfs: update dentry_unhash() comment vfs: push dentry_unhash on rename_dir into file systems vfs: push dentry_unhash on rmdir into file systems vfs: remove dget() from dentry_unhash() vfs: dentry_unhash immediately prior to rmdir vfs: Block mmapped writes while the fs is frozen ...
This commit is contained in:
commit
32e51f141f
@ -814,6 +814,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
|
|||||||
|
|
||||||
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
|
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
|
||||||
{
|
{
|
||||||
|
dentry_unhash(d);
|
||||||
return v9fs_remove(i, d, 1);
|
return v9fs_remove(i, d, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,6 +840,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct p9_fid *newdirfid;
|
struct p9_fid *newdirfid;
|
||||||
struct p9_wstat wstat;
|
struct p9_wstat wstat;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "\n");
|
P9_DPRINTK(P9_DEBUG_VFS, "\n");
|
||||||
retval = 0;
|
retval = 0;
|
||||||
old_inode = old_dentry->d_inode;
|
old_inode = old_dentry->d_inode;
|
||||||
|
@ -47,7 +47,7 @@ config FS_POSIX_ACL
|
|||||||
def_bool n
|
def_bool n
|
||||||
|
|
||||||
config EXPORTFS
|
config EXPORTFS
|
||||||
bool
|
tristate
|
||||||
|
|
||||||
config FILE_LOCKING
|
config FILE_LOCKING
|
||||||
bool "Enable POSIX file locking API" if EXPERT
|
bool "Enable POSIX file locking API" if EXPERT
|
||||||
|
@ -320,6 +320,8 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
dentry->d_inode->i_ino,
|
dentry->d_inode->i_ino,
|
||||||
(int)dentry->d_name.len, dentry->d_name.name);
|
(int)dentry->d_name.len, dentry->d_name.name);
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
return affs_remove_header(dentry);
|
return affs_remove_header(dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +419,9 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct buffer_head *bh = NULL;
|
struct buffer_head *bh = NULL;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
|
pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
|
||||||
(u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
|
(u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
|
||||||
(u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
|
(u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
|
||||||
|
@ -845,6 +845,8 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
_enter("{%x:%u},{%s}",
|
_enter("{%x:%u},{%s}",
|
||||||
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
|
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
ret = -ENAMETOOLONG;
|
ret = -ENAMETOOLONG;
|
||||||
if (dentry->d_name.len >= AFSNAMEMAX)
|
if (dentry->d_name.len >= AFSNAMEMAX)
|
||||||
goto error;
|
goto error;
|
||||||
@ -1146,6 +1148,9 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct key *key;
|
struct key *key;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
vnode = AFS_FS_I(old_dentry->d_inode);
|
vnode = AFS_FS_I(old_dentry->d_inode);
|
||||||
orig_dvnode = AFS_FS_I(old_dir);
|
orig_dvnode = AFS_FS_I(old_dir);
|
||||||
new_dvnode = AFS_FS_I(new_dir);
|
new_dvnode = AFS_FS_I(new_dir);
|
||||||
|
@ -583,6 +583,8 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
|
|||||||
if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
|
if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (atomic_dec_and_test(&ino->count)) {
|
if (atomic_dec_and_test(&ino->count)) {
|
||||||
p_ino = autofs4_dentry_ino(dentry->d_parent);
|
p_ino = autofs4_dentry_ino(dentry->d_parent);
|
||||||
if (p_ino && dentry->d_parent != dentry)
|
if (p_ino && dentry->d_parent != dentry)
|
||||||
|
@ -224,6 +224,9 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct bfs_sb_info *info;
|
struct bfs_sb_info *info;
|
||||||
int error = -ENOENT;
|
int error = -ENOENT;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
old_bh = new_bh = NULL;
|
old_bh = new_bh = NULL;
|
||||||
old_inode = old_dentry->d_inode;
|
old_inode = old_dentry->d_inode;
|
||||||
if (S_ISDIR(old_inode->i_mode))
|
if (S_ISDIR(old_inode->i_mode))
|
||||||
|
59
fs/buffer.c
59
fs/buffer.c
@ -2331,24 +2331,26 @@ EXPORT_SYMBOL(block_commit_write);
|
|||||||
* page lock we can determine safely if the page is beyond EOF. If it is not
|
* page lock we can determine safely if the page is beyond EOF. If it is not
|
||||||
* beyond EOF, then the page is guaranteed safe against truncation until we
|
* beyond EOF, then the page is guaranteed safe against truncation until we
|
||||||
* unlock the page.
|
* unlock the page.
|
||||||
|
*
|
||||||
|
* Direct callers of this function should call vfs_check_frozen() so that page
|
||||||
|
* fault does not busyloop until the fs is thawed.
|
||||||
*/
|
*/
|
||||||
int
|
int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||||
block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
get_block_t get_block)
|
||||||
get_block_t get_block)
|
|
||||||
{
|
{
|
||||||
struct page *page = vmf->page;
|
struct page *page = vmf->page;
|
||||||
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
|
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
|
||||||
unsigned long end;
|
unsigned long end;
|
||||||
loff_t size;
|
loff_t size;
|
||||||
int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
|
int ret;
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
size = i_size_read(inode);
|
size = i_size_read(inode);
|
||||||
if ((page->mapping != inode->i_mapping) ||
|
if ((page->mapping != inode->i_mapping) ||
|
||||||
(page_offset(page) > size)) {
|
(page_offset(page) > size)) {
|
||||||
/* page got truncated out from underneath us */
|
/* We overload EFAULT to mean page got truncated */
|
||||||
unlock_page(page);
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* page is wholly or partially inside EOF */
|
/* page is wholly or partially inside EOF */
|
||||||
@ -2361,18 +2363,41 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
ret = block_commit_write(page, 0, end);
|
ret = block_commit_write(page, 0, end);
|
||||||
|
|
||||||
if (unlikely(ret)) {
|
if (unlikely(ret < 0))
|
||||||
unlock_page(page);
|
goto out_unlock;
|
||||||
if (ret == -ENOMEM)
|
/*
|
||||||
ret = VM_FAULT_OOM;
|
* Freezing in progress? We check after the page is marked dirty and
|
||||||
else /* -ENOSPC, -EIO, etc */
|
* with page lock held so if the test here fails, we are sure freezing
|
||||||
ret = VM_FAULT_SIGBUS;
|
* code will wait during syncing until the page fault is done - at that
|
||||||
} else
|
* point page will be dirty and unlocked so freezing code will write it
|
||||||
ret = VM_FAULT_LOCKED;
|
* and writeprotect it again.
|
||||||
|
*/
|
||||||
out:
|
set_page_dirty(page);
|
||||||
|
if (inode->i_sb->s_frozen != SB_UNFROZEN) {
|
||||||
|
ret = -EAGAIN;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
out_unlock:
|
||||||
|
unlock_page(page);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(__block_page_mkwrite);
|
||||||
|
|
||||||
|
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||||
|
get_block_t get_block)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct super_block *sb = vma->vm_file->f_path.dentry->d_inode->i_sb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This check is racy but catches the common case. The check in
|
||||||
|
* __block_page_mkwrite() is reliable.
|
||||||
|
*/
|
||||||
|
vfs_check_frozen(sb, SB_FREEZE_WRITE);
|
||||||
|
ret = __block_page_mkwrite(vma, vmf, get_block);
|
||||||
|
return block_page_mkwrite_return(ret);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(block_page_mkwrite);
|
EXPORT_SYMBOL(block_page_mkwrite);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -336,6 +336,8 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
|
|||||||
int len = de->d_name.len;
|
int len = de->d_name.len;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
dentry_unhash(de);
|
||||||
|
|
||||||
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
|
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
/* VFS may delete the child */
|
/* VFS may delete the child */
|
||||||
@ -359,6 +361,9 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
int new_length = new_dentry->d_name.len;
|
int new_length = new_dentry->d_name.len;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
|
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
|
||||||
coda_i2f(new_dir), old_length, new_length,
|
coda_i2f(new_dir), old_length, new_length,
|
||||||
(const char *) old_name, (const char *)new_name);
|
(const char *) old_name, (const char *)new_name);
|
||||||
|
@ -1359,6 +1359,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct module *subsys_owner = NULL, *dead_item_owner = NULL;
|
struct module *subsys_owner = NULL, *dead_item_owner = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (dentry->d_parent == configfs_sb->s_root)
|
if (dentry->d_parent == configfs_sb->s_root)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
@ -521,6 +521,8 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct dentry *lower_dir_dentry;
|
struct dentry *lower_dir_dentry;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||||
dget(dentry);
|
dget(dentry);
|
||||||
lower_dir_dentry = lock_parent(lower_dentry);
|
lower_dir_dentry = lock_parent(lower_dentry);
|
||||||
@ -571,6 +573,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct dentry *lower_new_dir_dentry;
|
struct dentry *lower_new_dir_dentry;
|
||||||
struct dentry *trap = NULL;
|
struct dentry *trap = NULL;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
|
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
|
||||||
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
|
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
|
||||||
dget(lower_old_dentry);
|
dget(lower_old_dentry);
|
||||||
|
@ -326,6 +326,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct fat_slot_info sinfo;
|
struct fat_slot_info sinfo;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
lock_super(sb);
|
lock_super(sb);
|
||||||
/*
|
/*
|
||||||
* Check whether the directory is not in use, then check
|
* Check whether the directory is not in use, then check
|
||||||
@ -457,6 +459,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
|
|||||||
old_inode = old_dentry->d_inode;
|
old_inode = old_dentry->d_inode;
|
||||||
new_inode = new_dentry->d_inode;
|
new_inode = new_dentry->d_inode;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
err = fat_scan(old_dir, old_name, &old_sinfo);
|
err = fat_scan(old_dir, old_name, &old_sinfo);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
@ -824,6 +824,8 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct fat_slot_info sinfo;
|
struct fat_slot_info sinfo;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
lock_super(sb);
|
lock_super(sb);
|
||||||
|
|
||||||
err = fat_dir_empty(inode);
|
err = fat_dir_empty(inode);
|
||||||
@ -931,6 +933,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
int err, is_dir, update_dotdot, corrupt = 0;
|
int err, is_dir, update_dotdot, corrupt = 0;
|
||||||
struct super_block *sb = old_dir->i_sb;
|
struct super_block *sb = old_dir->i_sb;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
|
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
|
||||||
old_inode = old_dentry->d_inode;
|
old_inode = old_dentry->d_inode;
|
||||||
new_inode = new_dentry->d_inode;
|
new_inode = new_dentry->d_inode;
|
||||||
|
@ -667,6 +667,8 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
|
|||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
dentry_unhash(entry);
|
||||||
|
|
||||||
req->in.h.opcode = FUSE_RMDIR;
|
req->in.h.opcode = FUSE_RMDIR;
|
||||||
req->in.h.nodeid = get_node_id(dir);
|
req->in.h.nodeid = get_node_id(dir);
|
||||||
req->in.numargs = 1;
|
req->in.numargs = 1;
|
||||||
@ -691,6 +693,10 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
|
|||||||
struct fuse_rename_in inarg;
|
struct fuse_rename_in inarg;
|
||||||
struct fuse_conn *fc = get_fuse_conn(olddir);
|
struct fuse_conn *fc = get_fuse_conn(olddir);
|
||||||
struct fuse_req *req = fuse_get_req(fc);
|
struct fuse_req *req = fuse_get_req(fc);
|
||||||
|
|
||||||
|
if (newent->d_inode && S_ISDIR(newent->d_inode->i_mode))
|
||||||
|
dentry_unhash(newent);
|
||||||
|
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
@ -253,6 +253,9 @@ static int hfs_remove(struct inode *dir, struct dentry *dentry)
|
|||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
if (S_ISDIR(inode->i_mode))
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
|
if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
|
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
|
||||||
@ -283,6 +286,9 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
|
|
||||||
/* Unlink destination if it already exists */
|
/* Unlink destination if it already exists */
|
||||||
if (new_dentry->d_inode) {
|
if (new_dentry->d_inode) {
|
||||||
|
if (S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
res = hfs_remove(new_dir, new_dentry);
|
res = hfs_remove(new_dir, new_dentry);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
@ -370,6 +370,8 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (inode->i_size != 2)
|
if (inode->i_size != 2)
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
|
|
||||||
@ -467,10 +469,12 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
|
|
||||||
/* Unlink destination if it already exists */
|
/* Unlink destination if it already exists */
|
||||||
if (new_dentry->d_inode) {
|
if (new_dentry->d_inode) {
|
||||||
if (S_ISDIR(new_dentry->d_inode->i_mode))
|
if (S_ISDIR(new_dentry->d_inode->i_mode)) {
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
res = hfsplus_rmdir(new_dir, new_dentry);
|
res = hfsplus_rmdir(new_dir, new_dentry);
|
||||||
else
|
} else {
|
||||||
res = hfsplus_unlink(new_dir, new_dentry);
|
res = hfsplus_unlink(new_dir, new_dentry);
|
||||||
|
}
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -683,6 +683,8 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
|
|||||||
char *file;
|
char *file;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if ((file = dentry_name(dentry)) == NULL)
|
if ((file = dentry_name(dentry)) == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
err = do_rmdir(file);
|
err = do_rmdir(file);
|
||||||
@ -736,6 +738,9 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
|
|||||||
char *from_name, *to_name;
|
char *from_name, *to_name;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (to->d_inode && S_ISDIR(to->d_inode->i_mode))
|
||||||
|
dentry_unhash(to);
|
||||||
|
|
||||||
if ((from_name = dentry_name(from)) == NULL)
|
if ((from_name = dentry_name(from)) == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if ((to_name = dentry_name(to)) == NULL) {
|
if ((to_name = dentry_name(to)) == NULL) {
|
||||||
|
@ -395,7 +395,6 @@ again:
|
|||||||
|
|
||||||
dentry_unhash(dentry);
|
dentry_unhash(dentry);
|
||||||
if (!d_unhashed(dentry)) {
|
if (!d_unhashed(dentry)) {
|
||||||
dput(dentry);
|
|
||||||
hpfs_unlock(dir->i_sb);
|
hpfs_unlock(dir->i_sb);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
@ -403,7 +402,6 @@ again:
|
|||||||
!S_ISREG(inode->i_mode) ||
|
!S_ISREG(inode->i_mode) ||
|
||||||
get_write_access(inode)) {
|
get_write_access(inode)) {
|
||||||
d_rehash(dentry);
|
d_rehash(dentry);
|
||||||
dput(dentry);
|
|
||||||
} else {
|
} else {
|
||||||
struct iattr newattrs;
|
struct iattr newattrs;
|
||||||
/*printk("HPFS: truncating file before delete.\n");*/
|
/*printk("HPFS: truncating file before delete.\n");*/
|
||||||
@ -411,7 +409,6 @@ again:
|
|||||||
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
|
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
|
||||||
err = notify_change(dentry, &newattrs);
|
err = notify_change(dentry, &newattrs);
|
||||||
put_write_access(inode);
|
put_write_access(inode);
|
||||||
dput(dentry);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@ -442,6 +439,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
int err;
|
int err;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
hpfs_adjust_length(name, &len);
|
hpfs_adjust_length(name, &len);
|
||||||
hpfs_lock(dir->i_sb);
|
hpfs_lock(dir->i_sb);
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
@ -535,6 +534,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct fnode *fnode;
|
struct fnode *fnode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
if ((err = hpfs_chk_name(new_name, &new_len))) return err;
|
if ((err = hpfs_chk_name(new_name, &new_len))) return err;
|
||||||
err = 0;
|
err = 0;
|
||||||
hpfs_adjust_length(old_name, &old_len);
|
hpfs_adjust_length(old_name, &old_len);
|
||||||
|
@ -609,6 +609,8 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
|
|||||||
int ret;
|
int ret;
|
||||||
uint32_t now = get_seconds();
|
uint32_t now = get_seconds();
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
for (fd = f->dents ; fd; fd = fd->next) {
|
for (fd = f->dents ; fd; fd = fd->next) {
|
||||||
if (fd->ino)
|
if (fd->ino)
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
@ -784,6 +786,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t now;
|
uint32_t now;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
/* The VFS will check for us and prevent trying to rename a
|
/* The VFS will check for us and prevent trying to rename a
|
||||||
* file over a directory and vice versa, but if it's a directory,
|
* file over a directory and vice versa, but if it's a directory,
|
||||||
* the VFS can't check whether the victim is empty. The filesystem
|
* the VFS can't check whether the victim is empty. The filesystem
|
||||||
|
@ -360,6 +360,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
|
|||||||
|
|
||||||
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
|
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
/* Init inode for quota operations. */
|
/* Init inode for quota operations. */
|
||||||
dquot_initialize(dip);
|
dquot_initialize(dip);
|
||||||
dquot_initialize(ip);
|
dquot_initialize(ip);
|
||||||
@ -1095,6 +1097,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
|
jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
|
||||||
new_dentry->d_name.name);
|
new_dentry->d_name.name);
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
dquot_initialize(old_dir);
|
dquot_initialize(old_dir);
|
||||||
dquot_initialize(new_dir);
|
dquot_initialize(new_dir);
|
||||||
|
|
||||||
|
@ -273,6 +273,8 @@ static int logfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (!logfs_empty_dir(inode))
|
if (!logfs_empty_dir(inode))
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
|
|
||||||
@ -622,6 +624,9 @@ static int logfs_rename_cross(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
loff_t pos;
|
loff_t pos;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
/* 1. locate source dd */
|
/* 1. locate source dd */
|
||||||
err = logfs_get_dd(old_dir, old_dentry, &dd, &pos);
|
err = logfs_get_dd(old_dir, old_dentry, &dd, &pos);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -168,6 +168,8 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
|
|||||||
struct inode * inode = dentry->d_inode;
|
struct inode * inode = dentry->d_inode;
|
||||||
int err = -ENOTEMPTY;
|
int err = -ENOTEMPTY;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (minix_empty_dir(inode)) {
|
if (minix_empty_dir(inode)) {
|
||||||
err = minix_unlink(dir, dentry);
|
err = minix_unlink(dir, dentry);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -190,6 +192,9 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
|
|||||||
struct minix_dir_entry * old_de;
|
struct minix_dir_entry * old_de;
|
||||||
int err = -ENOENT;
|
int err = -ENOENT;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
old_de = minix_find_entry(old_dentry, &old_page);
|
old_de = minix_find_entry(old_dentry, &old_page);
|
||||||
if (!old_de)
|
if (!old_de)
|
||||||
goto out;
|
goto out;
|
||||||
|
384
fs/namei.c
384
fs/namei.c
@ -391,79 +391,28 @@ void path_put(struct path *path)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(path_put);
|
EXPORT_SYMBOL(path_put);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* nameidata_drop_rcu - drop this nameidata out of rcu-walk
|
|
||||||
* @nd: nameidata pathwalk data to drop
|
|
||||||
* Returns: 0 on success, -ECHILD on failure
|
|
||||||
*
|
|
||||||
* Path walking has 2 modes, rcu-walk and ref-walk (see
|
* Path walking has 2 modes, rcu-walk and ref-walk (see
|
||||||
* Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt
|
* Documentation/filesystems/path-lookup.txt). In situations when we can't
|
||||||
* to drop out of rcu-walk mode and take normal reference counts on dentries
|
* continue in RCU mode, we attempt to drop out of rcu-walk mode and grab
|
||||||
* and vfsmounts to transition to rcu-walk mode. __drop_rcu* functions take
|
* normal reference counts on dentries and vfsmounts to transition to rcu-walk
|
||||||
* refcounts at the last known good point before rcu-walk got stuck, so
|
* mode. Refcounts are grabbed at the last known good point before rcu-walk
|
||||||
* ref-walk may continue from there. If this is not successful (eg. a seqcount
|
* got stuck, so ref-walk may continue from there. If this is not successful
|
||||||
* has changed), then failure is returned and path walk restarts from the
|
* (eg. a seqcount has changed), then failure is returned and it's up to caller
|
||||||
* beginning in ref-walk mode.
|
* to restart the path walk from the beginning in ref-walk mode.
|
||||||
*
|
|
||||||
* nameidata_drop_rcu attempts to drop the current nd->path and nd->root into
|
|
||||||
* ref-walk. Must be called from rcu-walk context.
|
|
||||||
*/
|
*/
|
||||||
static int nameidata_drop_rcu(struct nameidata *nd)
|
|
||||||
{
|
|
||||||
struct fs_struct *fs = current->fs;
|
|
||||||
struct dentry *dentry = nd->path.dentry;
|
|
||||||
int want_root = 0;
|
|
||||||
|
|
||||||
BUG_ON(!(nd->flags & LOOKUP_RCU));
|
|
||||||
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
|
|
||||||
want_root = 1;
|
|
||||||
spin_lock(&fs->lock);
|
|
||||||
if (nd->root.mnt != fs->root.mnt ||
|
|
||||||
nd->root.dentry != fs->root.dentry)
|
|
||||||
goto err_root;
|
|
||||||
}
|
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (!__d_rcu_to_refcount(dentry, nd->seq))
|
|
||||||
goto err;
|
|
||||||
BUG_ON(nd->inode != dentry->d_inode);
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
if (want_root) {
|
|
||||||
path_get(&nd->root);
|
|
||||||
spin_unlock(&fs->lock);
|
|
||||||
}
|
|
||||||
mntget(nd->path.mnt);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
br_read_unlock(vfsmount_lock);
|
|
||||||
nd->flags &= ~LOOKUP_RCU;
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
err_root:
|
|
||||||
if (want_root)
|
|
||||||
spin_unlock(&fs->lock);
|
|
||||||
return -ECHILD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing. */
|
|
||||||
static inline int nameidata_drop_rcu_maybe(struct nameidata *nd)
|
|
||||||
{
|
|
||||||
if (nd->flags & LOOKUP_RCU)
|
|
||||||
return nameidata_drop_rcu(nd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk
|
* unlazy_walk - try to switch to ref-walk mode.
|
||||||
* @nd: nameidata pathwalk data to drop
|
* @nd: nameidata pathwalk data
|
||||||
* @dentry: dentry to drop
|
* @dentry: child of nd->path.dentry or NULL
|
||||||
* Returns: 0 on success, -ECHILD on failure
|
* Returns: 0 on success, -ECHILD on failure
|
||||||
*
|
*
|
||||||
* nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root,
|
* unlazy_walk attempts to legitimize the current nd->path, nd->root and dentry
|
||||||
* and dentry into ref-walk. @dentry must be a path found by a do_lookup call on
|
* for ref-walk mode. @dentry must be a path found by a do_lookup call on
|
||||||
* @nd. Must be called from rcu-walk context.
|
* @nd or NULL. Must be called from rcu-walk context.
|
||||||
*/
|
*/
|
||||||
static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry)
|
static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct fs_struct *fs = current->fs;
|
struct fs_struct *fs = current->fs;
|
||||||
struct dentry *parent = nd->path.dentry;
|
struct dentry *parent = nd->path.dentry;
|
||||||
@ -478,18 +427,25 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
|
|||||||
goto err_root;
|
goto err_root;
|
||||||
}
|
}
|
||||||
spin_lock(&parent->d_lock);
|
spin_lock(&parent->d_lock);
|
||||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
if (!dentry) {
|
||||||
if (!__d_rcu_to_refcount(dentry, nd->seq))
|
if (!__d_rcu_to_refcount(parent, nd->seq))
|
||||||
goto err;
|
goto err_parent;
|
||||||
/*
|
BUG_ON(nd->inode != parent->d_inode);
|
||||||
* If the sequence check on the child dentry passed, then the child has
|
} else {
|
||||||
* not been removed from its parent. This means the parent dentry must
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
* be valid and able to take a reference at this point.
|
if (!__d_rcu_to_refcount(dentry, nd->seq))
|
||||||
*/
|
goto err_child;
|
||||||
BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
|
/*
|
||||||
BUG_ON(!parent->d_count);
|
* If the sequence check on the child dentry passed, then
|
||||||
parent->d_count++;
|
* the child has not been removed from its parent. This
|
||||||
spin_unlock(&dentry->d_lock);
|
* means the parent dentry must be valid and able to take
|
||||||
|
* a reference at this point.
|
||||||
|
*/
|
||||||
|
BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
|
||||||
|
BUG_ON(!parent->d_count);
|
||||||
|
parent->d_count++;
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
}
|
||||||
spin_unlock(&parent->d_lock);
|
spin_unlock(&parent->d_lock);
|
||||||
if (want_root) {
|
if (want_root) {
|
||||||
path_get(&nd->root);
|
path_get(&nd->root);
|
||||||
@ -501,8 +457,10 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
|
|||||||
br_read_unlock(vfsmount_lock);
|
br_read_unlock(vfsmount_lock);
|
||||||
nd->flags &= ~LOOKUP_RCU;
|
nd->flags &= ~LOOKUP_RCU;
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
|
||||||
|
err_child:
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
err_parent:
|
||||||
spin_unlock(&parent->d_lock);
|
spin_unlock(&parent->d_lock);
|
||||||
err_root:
|
err_root:
|
||||||
if (want_root)
|
if (want_root)
|
||||||
@ -510,59 +468,6 @@ err_root:
|
|||||||
return -ECHILD;
|
return -ECHILD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing. */
|
|
||||||
static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry)
|
|
||||||
{
|
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
|
||||||
if (unlikely(nameidata_dentry_drop_rcu(nd, dentry))) {
|
|
||||||
nd->flags &= ~LOOKUP_RCU;
|
|
||||||
if (!(nd->flags & LOOKUP_ROOT))
|
|
||||||
nd->root.mnt = NULL;
|
|
||||||
rcu_read_unlock();
|
|
||||||
br_read_unlock(vfsmount_lock);
|
|
||||||
return -ECHILD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk
|
|
||||||
* @nd: nameidata pathwalk data to drop
|
|
||||||
* Returns: 0 on success, -ECHILD on failure
|
|
||||||
*
|
|
||||||
* nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk.
|
|
||||||
* nd->path should be the final element of the lookup, so nd->root is discarded.
|
|
||||||
* Must be called from rcu-walk context.
|
|
||||||
*/
|
|
||||||
static int nameidata_drop_rcu_last(struct nameidata *nd)
|
|
||||||
{
|
|
||||||
struct dentry *dentry = nd->path.dentry;
|
|
||||||
|
|
||||||
BUG_ON(!(nd->flags & LOOKUP_RCU));
|
|
||||||
nd->flags &= ~LOOKUP_RCU;
|
|
||||||
if (!(nd->flags & LOOKUP_ROOT))
|
|
||||||
nd->root.mnt = NULL;
|
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (!__d_rcu_to_refcount(dentry, nd->seq))
|
|
||||||
goto err_unlock;
|
|
||||||
BUG_ON(nd->inode != dentry->d_inode);
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
|
|
||||||
mntget(nd->path.mnt);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
br_read_unlock(vfsmount_lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_unlock:
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
rcu_read_unlock();
|
|
||||||
br_read_unlock(vfsmount_lock);
|
|
||||||
return -ECHILD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* release_open_intent - free up open intent resources
|
* release_open_intent - free up open intent resources
|
||||||
* @nd: pointer to nameidata
|
* @nd: pointer to nameidata
|
||||||
@ -606,26 +511,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||||||
return dentry;
|
return dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* handle_reval_path - force revalidation of a dentry
|
* complete_walk - successful completion of path walk
|
||||||
|
* @nd: pointer nameidata
|
||||||
*
|
*
|
||||||
* In some situations the path walking code will trust dentries without
|
* If we had been in RCU mode, drop out of it and legitimize nd->path.
|
||||||
* revalidating them. This causes problems for filesystems that depend on
|
* Revalidate the final result, unless we'd already done that during
|
||||||
* d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set
|
* the path walk or the filesystem doesn't ask for it. Return 0 on
|
||||||
* (which indicates that it's possible for the dentry to go stale), force
|
* success, -error on failure. In case of failure caller does not
|
||||||
* a d_revalidate call before proceeding.
|
* need to drop nd->path.
|
||||||
*
|
|
||||||
* Returns 0 if the revalidation was successful. If the revalidation fails,
|
|
||||||
* either return the error returned by d_revalidate or -ESTALE if the
|
|
||||||
* revalidation it just returned 0. If d_revalidate returns 0, we attempt to
|
|
||||||
* invalidate the dentry. It's up to the caller to handle putting references
|
|
||||||
* to the path if necessary.
|
|
||||||
*/
|
*/
|
||||||
static inline int handle_reval_path(struct nameidata *nd)
|
static int complete_walk(struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct dentry *dentry = nd->path.dentry;
|
struct dentry *dentry = nd->path.dentry;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
nd->flags &= ~LOOKUP_RCU;
|
||||||
|
if (!(nd->flags & LOOKUP_ROOT))
|
||||||
|
nd->root.mnt = NULL;
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
|
if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
|
br_read_unlock(vfsmount_lock);
|
||||||
|
return -ECHILD;
|
||||||
|
}
|
||||||
|
BUG_ON(nd->inode != dentry->d_inode);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
mntget(nd->path.mnt);
|
||||||
|
rcu_read_unlock();
|
||||||
|
br_read_unlock(vfsmount_lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (likely(!(nd->flags & LOOKUP_JUMPED)))
|
if (likely(!(nd->flags & LOOKUP_JUMPED)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -643,6 +561,7 @@ static inline int handle_reval_path(struct nameidata *nd)
|
|||||||
if (!status)
|
if (!status)
|
||||||
status = -ESTALE;
|
status = -ESTALE;
|
||||||
|
|
||||||
|
path_put(&nd->path);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,13 +1160,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
|
|||||||
if (likely(__follow_mount_rcu(nd, path, inode, false)))
|
if (likely(__follow_mount_rcu(nd, path, inode, false)))
|
||||||
return 0;
|
return 0;
|
||||||
unlazy:
|
unlazy:
|
||||||
if (dentry) {
|
if (unlazy_walk(nd, dentry))
|
||||||
if (nameidata_dentry_drop_rcu(nd, dentry))
|
return -ECHILD;
|
||||||
return -ECHILD;
|
|
||||||
} else {
|
|
||||||
if (nameidata_drop_rcu(nd))
|
|
||||||
return -ECHILD;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dentry = __d_lookup(parent, name);
|
dentry = __d_lookup(parent, name);
|
||||||
}
|
}
|
||||||
@ -1303,7 +1217,7 @@ static inline int may_lookup(struct nameidata *nd)
|
|||||||
int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
|
int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
|
||||||
if (err != -ECHILD)
|
if (err != -ECHILD)
|
||||||
return err;
|
return err;
|
||||||
if (nameidata_drop_rcu(nd))
|
if (unlazy_walk(nd, NULL))
|
||||||
return -ECHILD;
|
return -ECHILD;
|
||||||
}
|
}
|
||||||
return exec_permission(nd->inode, 0);
|
return exec_permission(nd->inode, 0);
|
||||||
@ -1357,8 +1271,12 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
if (unlikely(inode->i_op->follow_link) && follow) {
|
if (unlikely(inode->i_op->follow_link) && follow) {
|
||||||
if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
return -ECHILD;
|
if (unlikely(unlazy_walk(nd, path->dentry))) {
|
||||||
|
terminate_walk(nd);
|
||||||
|
return -ECHILD;
|
||||||
|
}
|
||||||
|
}
|
||||||
BUG_ON(inode != path->dentry->d_inode);
|
BUG_ON(inode != path->dentry->d_inode);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1657,18 +1575,8 @@ static int path_lookupat(int dfd, const char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
if (!err)
|
||||||
/* went all way through without dropping RCU */
|
err = complete_walk(nd);
|
||||||
BUG_ON(err);
|
|
||||||
if (nameidata_drop_rcu_last(nd))
|
|
||||||
err = -ECHILD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
err = handle_reval_path(nd);
|
|
||||||
if (err)
|
|
||||||
path_put(&nd->path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!err && nd->flags & LOOKUP_DIRECTORY) {
|
if (!err && nd->flags & LOOKUP_DIRECTORY) {
|
||||||
if (!nd->inode->i_op->lookup) {
|
if (!nd->inode->i_op->lookup) {
|
||||||
@ -2134,13 +2042,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case LAST_ROOT:
|
case LAST_ROOT:
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
error = complete_walk(nd);
|
||||||
if (nameidata_drop_rcu_last(nd))
|
|
||||||
return ERR_PTR(-ECHILD);
|
|
||||||
}
|
|
||||||
error = handle_reval_path(nd);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto exit;
|
return ERR_PTR(error);
|
||||||
audit_inode(pathname, nd->path.dentry);
|
audit_inode(pathname, nd->path.dentry);
|
||||||
if (open_flag & O_CREAT) {
|
if (open_flag & O_CREAT) {
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
@ -2148,10 +2052,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
}
|
}
|
||||||
goto ok;
|
goto ok;
|
||||||
case LAST_BIND:
|
case LAST_BIND:
|
||||||
/* can't be RCU mode here */
|
error = complete_walk(nd);
|
||||||
error = handle_reval_path(nd);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto exit;
|
return ERR_PTR(error);
|
||||||
audit_inode(pathname, dir);
|
audit_inode(pathname, dir);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
@ -2170,10 +2073,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
if (error) /* symlink */
|
if (error) /* symlink */
|
||||||
return NULL;
|
return NULL;
|
||||||
/* sayonara */
|
/* sayonara */
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
error = complete_walk(nd);
|
||||||
if (nameidata_drop_rcu_last(nd))
|
if (error)
|
||||||
return ERR_PTR(-ECHILD);
|
return ERR_PTR(-ECHILD);
|
||||||
}
|
|
||||||
|
|
||||||
error = -ENOTDIR;
|
error = -ENOTDIR;
|
||||||
if (nd->flags & LOOKUP_DIRECTORY) {
|
if (nd->flags & LOOKUP_DIRECTORY) {
|
||||||
@ -2185,11 +2087,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create side of things */
|
/* create side of things */
|
||||||
|
error = complete_walk(nd);
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
if (error)
|
||||||
if (nameidata_drop_rcu_last(nd))
|
return ERR_PTR(error);
|
||||||
return ERR_PTR(-ECHILD);
|
|
||||||
}
|
|
||||||
|
|
||||||
audit_inode(pathname, dir);
|
audit_inode(pathname, dir);
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
@ -2629,10 +2529,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We try to drop the dentry early: we should have
|
* The dentry_unhash() helper will try to drop the dentry early: we
|
||||||
* a usage count of 2 if we're the only user of this
|
* should have a usage count of 2 if we're the only user of this
|
||||||
* dentry, and if that is true (possibly after pruning
|
* dentry, and if that is true (possibly after pruning the dcache),
|
||||||
* the dcache), then we drop the dentry now.
|
* then we drop the dentry now.
|
||||||
*
|
*
|
||||||
* A low-level filesystem can, if it choses, legally
|
* A low-level filesystem can, if it choses, legally
|
||||||
* do a
|
* do a
|
||||||
@ -2645,10 +2545,9 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
|
|||||||
*/
|
*/
|
||||||
void dentry_unhash(struct dentry *dentry)
|
void dentry_unhash(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
dget(dentry);
|
|
||||||
shrink_dcache_parent(dentry);
|
shrink_dcache_parent(dentry);
|
||||||
spin_lock(&dentry->d_lock);
|
spin_lock(&dentry->d_lock);
|
||||||
if (dentry->d_count == 2)
|
if (dentry->d_count == 1)
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
@ -2664,25 +2563,26 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
mutex_lock(&dentry->d_inode->i_mutex);
|
mutex_lock(&dentry->d_inode->i_mutex);
|
||||||
dentry_unhash(dentry);
|
|
||||||
if (d_mountpoint(dentry))
|
|
||||||
error = -EBUSY;
|
|
||||||
else {
|
|
||||||
error = security_inode_rmdir(dir, dentry);
|
|
||||||
if (!error) {
|
|
||||||
error = dir->i_op->rmdir(dir, dentry);
|
|
||||||
if (!error) {
|
|
||||||
dentry->d_inode->i_flags |= S_DEAD;
|
|
||||||
dont_mount(dentry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
|
||||||
if (!error) {
|
|
||||||
d_delete(dentry);
|
|
||||||
}
|
|
||||||
dput(dentry);
|
|
||||||
|
|
||||||
|
error = -EBUSY;
|
||||||
|
if (d_mountpoint(dentry))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = security_inode_rmdir(dir, dentry);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = dir->i_op->rmdir(dir, dentry);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
dentry->d_inode->i_flags |= S_DEAD;
|
||||||
|
dont_mount(dentry);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||||
|
if (!error)
|
||||||
|
d_delete(dentry);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3053,12 +2953,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
|
|||||||
* HOWEVER, it relies on the assumption that any object with ->lookup()
|
* HOWEVER, it relies on the assumption that any object with ->lookup()
|
||||||
* has no more than 1 dentry. If "hybrid" objects will ever appear,
|
* has no more than 1 dentry. If "hybrid" objects will ever appear,
|
||||||
* we'd better make sure that there's no link(2) for them.
|
* we'd better make sure that there's no link(2) for them.
|
||||||
* d) some filesystems don't support opened-but-unlinked directories,
|
* d) conversion from fhandle to dentry may come in the wrong moment - when
|
||||||
* either because of layout or because they are not ready to deal with
|
|
||||||
* all cases correctly. The latter will be fixed (taking this sort of
|
|
||||||
* stuff into VFS), but the former is not going away. Solution: the same
|
|
||||||
* trick as in rmdir().
|
|
||||||
* e) conversion from fhandle to dentry may come in the wrong moment - when
|
|
||||||
* we are removing the target. Solution: we will have to grab ->i_mutex
|
* we are removing the target. Solution: we will have to grab ->i_mutex
|
||||||
* in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
|
* in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
|
||||||
* ->i_mutex on parents, which works but leads to some truly excessive
|
* ->i_mutex on parents, which works but leads to some truly excessive
|
||||||
@ -3068,7 +2963,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct inode *new_dir, struct dentry *new_dentry)
|
struct inode *new_dir, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct inode *target;
|
struct inode *target = new_dentry->d_inode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are going to change the parent - check write permissions,
|
* If we are going to change the parent - check write permissions,
|
||||||
@ -3084,26 +2979,24 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
target = new_dentry->d_inode;
|
|
||||||
if (target)
|
if (target)
|
||||||
mutex_lock(&target->i_mutex);
|
mutex_lock(&target->i_mutex);
|
||||||
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
|
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
else {
|
if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
|
||||||
if (target)
|
goto out;
|
||||||
dentry_unhash(new_dentry);
|
|
||||||
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||||
}
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
if (!error) {
|
target->i_flags |= S_DEAD;
|
||||||
target->i_flags |= S_DEAD;
|
dont_mount(new_dentry);
|
||||||
dont_mount(new_dentry);
|
|
||||||
}
|
|
||||||
mutex_unlock(&target->i_mutex);
|
|
||||||
if (d_unhashed(new_dentry))
|
|
||||||
d_rehash(new_dentry);
|
|
||||||
dput(new_dentry);
|
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
if (target)
|
||||||
|
mutex_unlock(&target->i_mutex);
|
||||||
if (!error)
|
if (!error)
|
||||||
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
|
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
|
||||||
d_move(old_dentry,new_dentry);
|
d_move(old_dentry,new_dentry);
|
||||||
@ -3113,7 +3006,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
|
static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
struct inode *new_dir, struct dentry *new_dentry)
|
struct inode *new_dir, struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
struct inode *target;
|
struct inode *target = new_dentry->d_inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
|
error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||||
@ -3121,19 +3014,22 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
dget(new_dentry);
|
dget(new_dentry);
|
||||||
target = new_dentry->d_inode;
|
|
||||||
if (target)
|
if (target)
|
||||||
mutex_lock(&target->i_mutex);
|
mutex_lock(&target->i_mutex);
|
||||||
|
|
||||||
|
error = -EBUSY;
|
||||||
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
|
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
|
||||||
error = -EBUSY;
|
goto out;
|
||||||
else
|
|
||||||
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||||
if (!error) {
|
if (error)
|
||||||
if (target)
|
goto out;
|
||||||
dont_mount(new_dentry);
|
|
||||||
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
|
if (target)
|
||||||
d_move(old_dentry, new_dentry);
|
dont_mount(new_dentry);
|
||||||
}
|
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
|
||||||
|
d_move(old_dentry, new_dentry);
|
||||||
|
out:
|
||||||
if (target)
|
if (target)
|
||||||
mutex_unlock(&target->i_mutex);
|
mutex_unlock(&target->i_mutex);
|
||||||
dput(new_dentry);
|
dput(new_dentry);
|
||||||
|
@ -1695,7 +1695,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
|
|||||||
|
|
||||||
static int flags_to_propagation_type(int flags)
|
static int flags_to_propagation_type(int flags)
|
||||||
{
|
{
|
||||||
int type = flags & ~MS_REC;
|
int type = flags & ~(MS_REC | MS_SILENT);
|
||||||
|
|
||||||
/* Fail if any non-propagation flags are set */
|
/* Fail if any non-propagation flags are set */
|
||||||
if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
|
if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
|
||||||
|
@ -1033,6 +1033,8 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
DPRINTK("ncp_rmdir: removing %s/%s\n",
|
DPRINTK("ncp_rmdir: removing %s/%s\n",
|
||||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
if (!d_unhashed(dentry))
|
if (!d_unhashed(dentry))
|
||||||
goto out;
|
goto out;
|
||||||
@ -1139,6 +1141,9 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
|
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
|
||||||
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
|
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
ncp_age_dentry(server, old_dentry);
|
ncp_age_dentry(server, old_dentry);
|
||||||
ncp_age_dentry(server, new_dentry);
|
ncp_age_dentry(server, new_dentry);
|
||||||
|
|
||||||
|
@ -334,6 +334,8 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct nilfs_transaction_info ti;
|
struct nilfs_transaction_info ti;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@ -369,6 +371,9 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct nilfs_transaction_info ti;
|
struct nilfs_transaction_info ti;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
|
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
|
||||||
if (unlikely(err))
|
if (unlikely(err))
|
||||||
return err;
|
return err;
|
||||||
|
@ -240,8 +240,12 @@ static int omfs_remove(struct inode *dir, struct dentry *dentry)
|
|||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode))
|
|
||||||
return -ENOTEMPTY;
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
if (!omfs_dir_is_empty(inode))
|
||||||
|
return -ENOTEMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
ret = omfs_delete_entry(dentry);
|
ret = omfs_delete_entry(dentry);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -378,6 +382,9 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (new_inode) {
|
if (new_inode) {
|
||||||
|
if (S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
/* overwriting existing file/dir */
|
/* overwriting existing file/dir */
|
||||||
err = omfs_remove(new_dir, new_dentry);
|
err = omfs_remove(new_dir, new_dentry);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -831,6 +831,8 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
INITIALIZE_PATH(path);
|
INITIALIZE_PATH(path);
|
||||||
struct reiserfs_dir_entry de;
|
struct reiserfs_dir_entry de;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
/* we will be doing 2 balancings and update 2 stat data, we change quotas
|
/* we will be doing 2 balancings and update 2 stat data, we change quotas
|
||||||
* of the owner of the directory and of the owner of the parent directory.
|
* of the owner of the directory and of the owner of the parent directory.
|
||||||
* The quota structure is possibly deleted only on last iput => outside
|
* The quota structure is possibly deleted only on last iput => outside
|
||||||
@ -1225,6 +1227,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
unsigned long savelink = 1;
|
unsigned long savelink = 1;
|
||||||
struct timespec ctime;
|
struct timespec ctime;
|
||||||
|
|
||||||
|
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
/* three balancings: (1) old name removal, (2) new name insertion
|
/* three balancings: (1) old name removal, (2) new name insertion
|
||||||
and (3) maybe "save" link insertion
|
and (3) maybe "save" link insertion
|
||||||
stat data updates: (1) old directory,
|
stat data updates: (1) old directory,
|
||||||
|
@ -105,7 +105,6 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||||
if (!error)
|
if (!error)
|
||||||
d_delete(dentry);
|
d_delete(dentry);
|
||||||
dput(dentry);
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,8 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
|
|||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int err = -ENOTEMPTY;
|
int err = -ENOTEMPTY;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
if (sysv_empty_dir(inode)) {
|
if (sysv_empty_dir(inode)) {
|
||||||
err = sysv_unlink(dir, dentry);
|
err = sysv_unlink(dir, dentry);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -222,6 +224,9 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
|
|||||||
struct sysv_dir_entry * old_de;
|
struct sysv_dir_entry * old_de;
|
||||||
int err = -ENOENT;
|
int err = -ENOENT;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
old_de = sysv_find_entry(old_dentry, &old_page);
|
old_de = sysv_find_entry(old_dentry, &old_page);
|
||||||
if (!old_de)
|
if (!old_de)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -656,6 +656,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
||||||
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
|
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Budget request settings: deletion direntry, deletion inode and
|
* Budget request settings: deletion direntry, deletion inode and
|
||||||
* changing the parent inode. If budgeting fails, go ahead anyway
|
* changing the parent inode. If budgeting fails, go ahead anyway
|
||||||
@ -976,6 +978,9 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
|
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Budget request settings: deletion direntry, new direntry, removing
|
* Budget request settings: deletion direntry, new direntry, removing
|
||||||
* the old inode, and changing old and new parent directory inodes.
|
* the old inode, and changing old and new parent directory inodes.
|
||||||
|
@ -783,6 +783,8 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
|
|||||||
struct fileIdentDesc *fi, cfi;
|
struct fileIdentDesc *fi, cfi;
|
||||||
struct kernel_lb_addr tloc;
|
struct kernel_lb_addr tloc;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
retval = -ENOENT;
|
retval = -ENOENT;
|
||||||
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
|
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
|
||||||
if (!fi)
|
if (!fi)
|
||||||
@ -1081,6 +1083,9 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct kernel_lb_addr tloc;
|
struct kernel_lb_addr tloc;
|
||||||
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
|
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
|
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
|
||||||
if (ofi) {
|
if (ofi) {
|
||||||
if (ofibh.sbh != ofibh.ebh)
|
if (ofibh.sbh != ofibh.ebh)
|
||||||
|
@ -258,6 +258,8 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
|
|||||||
struct inode * inode = dentry->d_inode;
|
struct inode * inode = dentry->d_inode;
|
||||||
int err= -ENOTEMPTY;
|
int err= -ENOTEMPTY;
|
||||||
|
|
||||||
|
dentry_unhash(dentry);
|
||||||
|
|
||||||
lock_ufs(dir->i_sb);
|
lock_ufs(dir->i_sb);
|
||||||
if (ufs_empty_dir (inode)) {
|
if (ufs_empty_dir (inode)) {
|
||||||
err = ufs_unlink(dir, dentry);
|
err = ufs_unlink(dir, dentry);
|
||||||
@ -282,6 +284,9 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
struct ufs_dir_entry *old_de;
|
struct ufs_dir_entry *old_de;
|
||||||
int err = -ENOENT;
|
int err = -ENOENT;
|
||||||
|
|
||||||
|
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||||
|
dentry_unhash(new_dentry);
|
||||||
|
|
||||||
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
||||||
if (!old_de)
|
if (!old_de)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -217,8 +217,24 @@ int cont_write_begin(struct file *, struct address_space *, loff_t,
|
|||||||
get_block_t *, loff_t *);
|
get_block_t *, loff_t *);
|
||||||
int generic_cont_expand_simple(struct inode *inode, loff_t size);
|
int generic_cont_expand_simple(struct inode *inode, loff_t size);
|
||||||
int block_commit_write(struct page *page, unsigned from, unsigned to);
|
int block_commit_write(struct page *page, unsigned from, unsigned to);
|
||||||
|
int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||||
|
get_block_t get_block);
|
||||||
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||||
get_block_t get_block);
|
get_block_t get_block);
|
||||||
|
/* Convert errno to return value from ->page_mkwrite() call */
|
||||||
|
static inline int block_page_mkwrite_return(int err)
|
||||||
|
{
|
||||||
|
if (err == 0)
|
||||||
|
return VM_FAULT_LOCKED;
|
||||||
|
if (err == -EFAULT)
|
||||||
|
return VM_FAULT_NOPAGE;
|
||||||
|
if (err == -ENOMEM)
|
||||||
|
return VM_FAULT_OOM;
|
||||||
|
if (err == -EAGAIN)
|
||||||
|
return VM_FAULT_RETRY;
|
||||||
|
/* -ENOSPC, -EDQUOT, -EIO ... */
|
||||||
|
return VM_FAULT_SIGBUS;
|
||||||
|
}
|
||||||
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
|
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
|
||||||
int block_truncate_page(struct address_space *, loff_t, get_block_t *);
|
int block_truncate_page(struct address_space *, loff_t, get_block_t *);
|
||||||
int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
|
int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
|
||||||
|
Loading…
Reference in New Issue
Block a user