mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 05:11:48 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull parallel filesystem directory handling update from Al Viro. This is the main parallel directory work by Al that makes the vfs layer able to do lookup and readdir in parallel within a single directory. That's a big change, since this used to be all protected by the directory inode mutex. The inode mutex is replaced by an rwsem, and serialization of lookups of a single name is done by a "in-progress" dentry marker. The series begins with xattr cleanups, and then ends with switching filesystems over to actually doing the readdir in parallel (switching to the "iterate_shared()" that only takes the read lock). A more detailed explanation of the process from Al Viro: "The xattr work starts with some acl fixes, then switches ->getxattr to passing inode and dentry separately. This is the point where the things start to get tricky - that got merged into the very beginning of the -rc3-based #work.lookups, to allow untangling the security_d_instantiate() mess. The xattr work itself proceeds to switch a lot of filesystems to generic_...xattr(); no complications there. After that initial xattr work, the series then does the following: - untangle security_d_instantiate() - convert a bunch of open-coded lookup_one_len_unlocked() to calls of that thing; one such place (in overlayfs) actually yields a trivial conflict with overlayfs fixes later in the cycle - overlayfs ended up switching to a variant of lookup_one_len_unlocked() sans the permission checks. I would've dropped that commit (it gets overridden on merge from #ovl-fixes in #for-next; proper resolution is to use the variant in mainline fs/overlayfs/super.c), but I didn't want to rebase the damn thing - it was fairly late in the cycle... - some filesystems had managed to depend on lookup/lookup exclusion for *fs-internal* data structures in a way that would break if we relaxed the VFS exclusion. Fixing hadn't been hard, fortunately. - core of that series - parallel lookup machinery, replacing ->i_mutex with rwsem, making lookup_slow() take it only shared. At that point lookups happen in parallel; lookups on the same name wait for the in-progress one to be done with that dentry. Surprisingly little code, at that - almost all of it is in fs/dcache.c, with fs/namei.c changes limited to lookup_slow() - making it use the new primitive and actually switching to locking shared. - parallel readdir stuff - first of all, we provide the exclusion on per-struct file basis, same as we do for read() vs lseek() for regular files. That takes care of most of the needed exclusion in readdir/readdir; however, these guys are trickier than lookups, so I went for switching them one-by-one. To do that, a new method '->iterate_shared()' is added and filesystems are switched to it as they are either confirmed to be OK with shared lock on directory or fixed to be OK with that. I hope to kill the original method come next cycle (almost all in-tree filesystems are switched already), but it's still not quite finished. - several filesystems get switched to parallel readdir. The interesting part here is dealing with dcache preseeding by readdir; that needs minor adjustment to be safe with directory locked only shared. Most of the filesystems doing that got switched to in those commits. Important exception: NFS. Turns out that NFS folks, with their, er, insistence on VFS getting the fuck out of the way of the Smart Filesystem Code That Knows How And What To Lock(tm) have grown the locking of their own. They had their own homegrown rwsem, with lookup/readdir/atomic_open being *writers* (sillyunlink is the reader there). Of course, with VFS getting the fuck out of the way, as requested, the actual smarts of the smart filesystem code etc. had become exposed... - do_last/lookup_open/atomic_open cleanups. As the result, open() without O_CREAT locks the directory only shared. Including the ->atomic_open() case. Backmerge from #for-linus in the middle of that - atomic_open() fix got brought in. - then comes NFS switch to saner (VFS-based ;-) locking, killing the homegrown "lookup and readdir are writers" kinda-sorta rwsem. All exclusion for sillyunlink/lookup is done by the parallel lookups mechanism. Exclusion between sillyunlink and rmdir is a real rwsem now - rmdir being the writer. Result: NFS lookups/readdirs/O_CREAT-less opens happen in parallel now. - the rest of the series consists of switching a lot of filesystems to parallel readdir; in a lot of cases ->llseek() gets simplified as well. One backmerge in there (again, #for-linus - rockridge fix)" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (74 commits) ext4: switch to ->iterate_shared() hfs: switch to ->iterate_shared() hfsplus: switch to ->iterate_shared() hostfs: switch to ->iterate_shared() hpfs: switch to ->iterate_shared() hpfs: handle allocation failures in hpfs_add_pos() gfs2: switch to ->iterate_shared() f2fs: switch to ->iterate_shared() afs: switch to ->iterate_shared() befs: switch to ->iterate_shared() befs: constify stuff a bit isofs: switch to ->iterate_shared() get_acorn_filename(): deobfuscate a bit btrfs: switch to ->iterate_shared() logfs: no need to lock directory in lseek switch ecryptfs to ->iterate_shared 9p: switch to ->iterate_shared() fat: switch to ->iterate_shared() romfs, squashfs: switch to ->iterate_shared() more trivial ->iterate_shared conversions ...
This commit is contained in:
commit
7f427d3a60
@ -525,3 +525,56 @@ in your dentry operations instead.
|
||||
set_delayed_call() where it used to set *cookie.
|
||||
->put_link() is gone - just give the destructor to set_delayed_call()
|
||||
in ->get_link().
|
||||
--
|
||||
[mandatory]
|
||||
->getxattr() and xattr_handler.get() get dentry and inode passed separately.
|
||||
dentry might be yet to be attached to inode, so do _not_ use its ->d_inode
|
||||
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
|
||||
called before we attach dentry to inode.
|
||||
--
|
||||
[mandatory]
|
||||
symlinks are no longer the only inodes that do *not* have i_bdev/i_cdev/
|
||||
i_pipe/i_link union zeroed out at inode eviction. As the result, you can't
|
||||
assume that non-NULL value in ->i_nlink at ->destroy_inode() implies that
|
||||
it's a symlink. Checking ->i_mode is really needed now. In-tree we had
|
||||
to fix shmem_destroy_callback() that used to take that kind of shortcut;
|
||||
watch out, since that shortcut is no longer valid.
|
||||
--
|
||||
[mandatory]
|
||||
->i_mutex is replaced with ->i_rwsem now. inode_lock() et.al. work as
|
||||
they used to - they just take it exclusive. However, ->lookup() may be
|
||||
called with parent locked shared. Its instances must not
|
||||
* use d_instantiate) and d_rehash() separately - use d_add() or
|
||||
d_splice_alias() instead.
|
||||
* use d_rehash() alone - call d_add(new_dentry, NULL) instead.
|
||||
* in the unlikely case when (read-only) access to filesystem
|
||||
data structures needs exclusion for some reason, arrange it
|
||||
yourself. None of the in-tree filesystems needed that.
|
||||
* rely on ->d_parent and ->d_name not changing after dentry has
|
||||
been fed to d_add() or d_splice_alias(). Again, none of the
|
||||
in-tree instances relied upon that.
|
||||
We are guaranteed that lookups of the same name in the same directory
|
||||
will not happen in parallel ("same" in the sense of your ->d_compare()).
|
||||
Lookups on different names in the same directory can and do happen in
|
||||
parallel now.
|
||||
--
|
||||
[recommended]
|
||||
->iterate_shared() is added; it's a parallel variant of ->iterate().
|
||||
Exclusion on struct file level is still provided (as well as that
|
||||
between it and lseek on the same struct file), but if your directory
|
||||
has been opened several times, you can get these called in parallel.
|
||||
Exclusion between that method and all directory-modifying ones is
|
||||
still provided, of course.
|
||||
|
||||
Often enough ->iterate() can serve as ->iterate_shared() without any
|
||||
changes - it is a read-only operation, after all. If you have any
|
||||
per-inode or per-dentry in-core data structures modified by ->iterate(),
|
||||
you might need something to serialize the access to them. If you
|
||||
do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for
|
||||
that; look for in-tree examples.
|
||||
|
||||
Old method is only used if the new one is absent; eventually it will
|
||||
be removed. Switch while you still can; the old one won't stay.
|
||||
--
|
||||
[mandatory]
|
||||
->atomic_open() calls without O_CREAT may happen in parallel.
|
||||
|
@ -147,7 +147,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
|
||||
long __user *, basep)
|
||||
{
|
||||
int error;
|
||||
struct fd arg = fdget(fd);
|
||||
struct fd arg = fdget_pos(fd);
|
||||
struct osf_dirent_callback buf = {
|
||||
.ctx.actor = osf_filldir,
|
||||
.dirent = dirent,
|
||||
@ -164,7 +164,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
|
||||
if (count != buf.count)
|
||||
error = count - buf.count;
|
||||
|
||||
fdput(arg);
|
||||
fdput_pos(arg);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ const struct file_operations spufs_context_fops = {
|
||||
.release = spufs_dir_close,
|
||||
.llseek = dcache_dir_lseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = dcache_readdir,
|
||||
.iterate_shared = dcache_readdir,
|
||||
.fsync = noop_fsync,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(spufs_context_fops);
|
||||
|
@ -1865,7 +1865,6 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin)
|
||||
int api32 = ll_need_32bit_api(sbi);
|
||||
loff_t ret = -EINVAL;
|
||||
|
||||
inode_lock(inode);
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
@ -1903,7 +1902,6 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1922,7 +1920,7 @@ const struct file_operations ll_dir_operations = {
|
||||
.open = ll_dir_open,
|
||||
.release = ll_dir_release,
|
||||
.read = generic_read_dir,
|
||||
.iterate = ll_readdir,
|
||||
.iterate_shared = ll_readdir,
|
||||
.unlocked_ioctl = ll_dir_ioctl,
|
||||
.fsync = ll_fsync,
|
||||
};
|
||||
|
@ -1042,8 +1042,8 @@ static inline __u64 ll_file_maxbytes(struct inode *inode)
|
||||
/* llite/xattr.c */
|
||||
int ll_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
ssize_t ll_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size);
|
||||
ssize_t ll_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size);
|
||||
ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
int ll_removexattr(struct dentry *dentry, const char *name);
|
||||
|
||||
|
@ -451,11 +451,9 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssize_t ll_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ssize_t ll_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
LASSERT(inode);
|
||||
LASSERT(name);
|
||||
|
||||
|
@ -93,7 +93,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
|
||||
* instantiating the inode (v9fs_inode_from_fid)
|
||||
*/
|
||||
acl = get_cached_acl(inode, type);
|
||||
BUG_ON(acl == ACL_NOT_CACHED);
|
||||
BUG_ON(is_uncached_acl(acl));
|
||||
return acl;
|
||||
}
|
||||
|
||||
@ -213,8 +213,8 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
|
||||
}
|
||||
|
||||
static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct v9fs_session_info *v9ses;
|
||||
struct posix_acl *acl;
|
||||
@ -227,7 +227,7 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
|
||||
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
|
||||
return v9fs_xattr_get(dentry, handler->name, buffer, size);
|
||||
|
||||
acl = v9fs_get_cached_acl(d_inode(dentry), handler->flags);
|
||||
acl = v9fs_get_cached_acl(inode, handler->flags);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
|
@ -246,7 +246,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
|
||||
const struct file_operations v9fs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.llseek = generic_file_llseek,
|
||||
.iterate = v9fs_dir_readdir,
|
||||
.iterate_shared = v9fs_dir_readdir,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
};
|
||||
@ -254,7 +254,7 @@ const struct file_operations v9fs_dir_operations = {
|
||||
const struct file_operations v9fs_dir_operations_dotl = {
|
||||
.read = generic_read_dir,
|
||||
.llseek = generic_file_llseek,
|
||||
.iterate = v9fs_dir_readdir_dotl,
|
||||
.iterate_shared = v9fs_dir_readdir_dotl,
|
||||
.open = v9fs_file_open,
|
||||
.release = v9fs_dir_release,
|
||||
.fsync = v9fs_file_fsync_dotl,
|
||||
|
@ -1071,7 +1071,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
if (IS_ERR(st))
|
||||
return PTR_ERR(st);
|
||||
|
||||
v9fs_stat2inode(st, d_inode(dentry), d_inode(dentry)->i_sb);
|
||||
v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb);
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
|
||||
p9stat_free(st);
|
||||
|
@ -138,8 +138,8 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
}
|
||||
|
||||
static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
const char *full_name = xattr_full_name(handler, name);
|
||||
|
||||
|
@ -20,7 +20,7 @@ static int affs_readdir(struct file *, struct dir_context *);
|
||||
const struct file_operations affs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.llseek = generic_file_llseek,
|
||||
.iterate = affs_readdir,
|
||||
.iterate_shared = affs_readdir,
|
||||
.fsync = affs_file_fsync,
|
||||
};
|
||||
|
||||
|
16
fs/afs/dir.c
16
fs/afs/dir.c
@ -43,7 +43,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
const struct file_operations afs_dir_file_operations = {
|
||||
.open = afs_dir_open,
|
||||
.release = afs_release,
|
||||
.iterate = afs_readdir,
|
||||
.iterate_shared = afs_readdir,
|
||||
.lock = afs_lock,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
@ -128,7 +128,7 @@ struct afs_lookup_cookie {
|
||||
/*
|
||||
* check that a directory page is valid
|
||||
*/
|
||||
static inline void afs_dir_check_page(struct inode *dir, struct page *page)
|
||||
static inline bool afs_dir_check_page(struct inode *dir, struct page *page)
|
||||
{
|
||||
struct afs_dir_page *dbuf;
|
||||
loff_t latter;
|
||||
@ -168,11 +168,11 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page)
|
||||
}
|
||||
|
||||
SetPageChecked(page);
|
||||
return;
|
||||
return true;
|
||||
|
||||
error:
|
||||
SetPageChecked(page);
|
||||
SetPageError(page);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -196,10 +196,10 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
|
||||
page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
|
||||
if (!IS_ERR(page)) {
|
||||
kmap(page);
|
||||
if (!PageChecked(page))
|
||||
afs_dir_check_page(dir, page);
|
||||
if (PageError(page))
|
||||
goto fail;
|
||||
if (unlikely(!PageChecked(page))) {
|
||||
if (PageError(page) || !afs_dir_check_page(dir, page))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return page;
|
||||
|
||||
|
@ -39,7 +39,7 @@ const struct file_operations autofs4_root_operations = {
|
||||
.open = dcache_dir_open,
|
||||
.release = dcache_dir_close,
|
||||
.read = generic_read_dir,
|
||||
.iterate = dcache_readdir,
|
||||
.iterate_shared = dcache_readdir,
|
||||
.llseek = dcache_dir_lseek,
|
||||
.unlocked_ioctl = autofs4_root_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
@ -51,7 +51,7 @@ const struct file_operations autofs4_dir_operations = {
|
||||
.open = autofs4_dir_open,
|
||||
.release = dcache_dir_close,
|
||||
.read = generic_read_dir,
|
||||
.iterate = dcache_readdir,
|
||||
.iterate_shared = dcache_readdir,
|
||||
.llseek = dcache_dir_lseek,
|
||||
};
|
||||
|
||||
|
@ -106,8 +106,8 @@ static int bad_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static ssize_t bad_inode_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static ssize_t bad_inode_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ BEFS_I(const struct inode *inode)
|
||||
}
|
||||
|
||||
static inline befs_blocknr_t
|
||||
iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
|
||||
iaddr2blockno(struct super_block *sb, const befs_inode_addr *iaddr)
|
||||
{
|
||||
return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
|
||||
iaddr->start);
|
||||
@ -141,7 +141,7 @@ befs_iaddrs_per_block(struct super_block *sb)
|
||||
}
|
||||
|
||||
static inline int
|
||||
befs_iaddr_is_empty(befs_inode_addr * iaddr)
|
||||
befs_iaddr_is_empty(const befs_inode_addr *iaddr)
|
||||
{
|
||||
return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
|
||||
}
|
||||
|
@ -88,15 +88,15 @@ struct befs_btree_node {
|
||||
static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
|
||||
|
||||
/* local functions */
|
||||
static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
||||
static int befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
|
||||
befs_btree_super * bt_super,
|
||||
struct befs_btree_node *this_node,
|
||||
befs_off_t * node_off);
|
||||
|
||||
static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
||||
static int befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
|
||||
befs_btree_super * sup);
|
||||
|
||||
static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
||||
static int befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
|
||||
struct befs_btree_node *node,
|
||||
befs_off_t node_off);
|
||||
|
||||
@ -134,7 +134,7 @@ static int befs_compare_strings(const void *key1, int keylen1,
|
||||
* On failure, BEFS_ERR is returned.
|
||||
*/
|
||||
static int
|
||||
befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
|
||||
befs_btree_super * sup)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
@ -193,7 +193,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
|
||||
*/
|
||||
|
||||
static int
|
||||
befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
|
||||
struct befs_btree_node *node, befs_off_t node_off)
|
||||
{
|
||||
uint off = 0;
|
||||
@ -247,7 +247,7 @@ befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
|
||||
* actuall value stored with the key.
|
||||
*/
|
||||
int
|
||||
befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
|
||||
const char *key, befs_off_t * value)
|
||||
{
|
||||
struct befs_btree_node *this_node;
|
||||
@ -416,7 +416,7 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node,
|
||||
* until the (key_no)th key is found or the tree is out of keys.
|
||||
*/
|
||||
int
|
||||
befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
|
||||
loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
|
||||
befs_off_t * value)
|
||||
{
|
||||
@ -548,7 +548,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
||||
* Also checks for an empty tree. If there are no keys, returns BEFS_BT_EMPTY.
|
||||
*/
|
||||
static int
|
||||
befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
|
||||
befs_btree_super *bt_super,
|
||||
struct befs_btree_node *this_node,
|
||||
befs_off_t * node_off)
|
||||
|
@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
|
||||
int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
|
||||
int befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
|
||||
const char *key, befs_off_t * value);
|
||||
|
||||
int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
|
||||
int befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
|
||||
loff_t key_no, size_t bufsize, char *keybuf,
|
||||
size_t * keysize, befs_off_t * value);
|
||||
|
||||
|
@ -21,16 +21,16 @@
|
||||
const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
|
||||
|
||||
static int befs_find_brun_direct(struct super_block *sb,
|
||||
befs_data_stream * data,
|
||||
const befs_data_stream *data,
|
||||
befs_blocknr_t blockno, befs_block_run * run);
|
||||
|
||||
static int befs_find_brun_indirect(struct super_block *sb,
|
||||
befs_data_stream * data,
|
||||
const befs_data_stream *data,
|
||||
befs_blocknr_t blockno,
|
||||
befs_block_run * run);
|
||||
|
||||
static int befs_find_brun_dblindirect(struct super_block *sb,
|
||||
befs_data_stream * data,
|
||||
const befs_data_stream *data,
|
||||
befs_blocknr_t blockno,
|
||||
befs_block_run * run);
|
||||
|
||||
@ -45,7 +45,7 @@ static int befs_find_brun_dblindirect(struct super_block *sb,
|
||||
* if you don't need to know offset just set @off = NULL.
|
||||
*/
|
||||
struct buffer_head *
|
||||
befs_read_datastream(struct super_block *sb, befs_data_stream * ds,
|
||||
befs_read_datastream(struct super_block *sb, const befs_data_stream *ds,
|
||||
befs_off_t pos, uint * off)
|
||||
{
|
||||
struct buffer_head *bh = NULL;
|
||||
@ -87,7 +87,7 @@ befs_read_datastream(struct super_block *sb, befs_data_stream * ds,
|
||||
* 2001-11-15 Will Dyson
|
||||
*/
|
||||
int
|
||||
befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
|
||||
befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
|
||||
befs_blocknr_t fblock, befs_block_run * run)
|
||||
{
|
||||
int err;
|
||||
@ -122,8 +122,8 @@ befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
|
||||
* Returns the number of bytes read
|
||||
*/
|
||||
size_t
|
||||
befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
|
||||
befs_off_t len)
|
||||
befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds,
|
||||
void *buff, befs_off_t len)
|
||||
{
|
||||
befs_off_t bytes_read = 0; /* bytes readed */
|
||||
u16 plen;
|
||||
@ -163,7 +163,7 @@ befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
|
||||
*/
|
||||
|
||||
befs_blocknr_t
|
||||
befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
|
||||
befs_count_blocks(struct super_block *sb, const befs_data_stream *ds)
|
||||
{
|
||||
befs_blocknr_t blocks;
|
||||
befs_blocknr_t datablocks; /* File data blocks */
|
||||
@ -243,11 +243,11 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
|
||||
2001-11-15 Will Dyson
|
||||
*/
|
||||
static int
|
||||
befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
|
||||
befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data,
|
||||
befs_blocknr_t blockno, befs_block_run * run)
|
||||
{
|
||||
int i;
|
||||
befs_block_run *array = data->direct;
|
||||
const befs_block_run *array = data->direct;
|
||||
befs_blocknr_t sum;
|
||||
befs_blocknr_t max_block =
|
||||
data->max_direct_range >> BEFS_SB(sb)->block_shift;
|
||||
@ -304,7 +304,8 @@ befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
|
||||
*/
|
||||
static int
|
||||
befs_find_brun_indirect(struct super_block *sb,
|
||||
befs_data_stream * data, befs_blocknr_t blockno,
|
||||
const befs_data_stream *data,
|
||||
befs_blocknr_t blockno,
|
||||
befs_block_run * run)
|
||||
{
|
||||
int i, j;
|
||||
@ -412,7 +413,8 @@ befs_find_brun_indirect(struct super_block *sb,
|
||||
*/
|
||||
static int
|
||||
befs_find_brun_dblindirect(struct super_block *sb,
|
||||
befs_data_stream * data, befs_blocknr_t blockno,
|
||||
const befs_data_stream *data,
|
||||
befs_blocknr_t blockno,
|
||||
befs_block_run * run)
|
||||
{
|
||||
int dblindir_indx;
|
||||
|
@ -4,16 +4,17 @@
|
||||
*/
|
||||
|
||||
struct buffer_head *befs_read_datastream(struct super_block *sb,
|
||||
befs_data_stream * ds, befs_off_t pos,
|
||||
uint * off);
|
||||
const befs_data_stream *ds,
|
||||
befs_off_t pos, uint * off);
|
||||
|
||||
int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
|
||||
int befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
|
||||
befs_blocknr_t fblock, befs_block_run * run);
|
||||
|
||||
size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
|
||||
size_t befs_read_lsymlink(struct super_block *sb, const befs_data_stream *data,
|
||||
void *buff, befs_off_t len);
|
||||
|
||||
befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
|
||||
befs_blocknr_t befs_count_blocks(struct super_block *sb,
|
||||
const befs_data_stream *ds);
|
||||
|
||||
extern const befs_inode_addr BAD_IADDR;
|
||||
|
||||
|
@ -66,7 +66,7 @@ static struct kmem_cache *befs_inode_cachep;
|
||||
|
||||
static const struct file_operations befs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.iterate = befs_readdir,
|
||||
.iterate_shared = befs_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
@ -157,7 +157,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;
|
||||
const befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;
|
||||
befs_off_t offset;
|
||||
int ret;
|
||||
int utfnamelen;
|
||||
@ -207,7 +207,7 @@ befs_readdir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
|
||||
const befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
|
||||
befs_off_t value;
|
||||
int result;
|
||||
size_t keysize;
|
||||
|
@ -70,7 +70,7 @@ static int bfs_readdir(struct file *f, struct dir_context *ctx)
|
||||
|
||||
const struct file_operations bfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.iterate = bfs_readdir,
|
||||
.iterate_shared = bfs_readdir,
|
||||
.fsync = generic_file_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -63,9 +63,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
|
||||
}
|
||||
kfree(value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -10181,7 +10181,7 @@ static const struct inode_operations btrfs_dir_ro_inode_operations = {
|
||||
static const struct file_operations btrfs_dir_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = btrfs_real_readdir,
|
||||
.iterate_shared = btrfs_real_readdir,
|
||||
.unlocked_ioctl = btrfs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = btrfs_ioctl,
|
||||
|
@ -837,9 +837,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
|
||||
struct dentry *dentry;
|
||||
int error;
|
||||
|
||||
error = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
if (error == -EINTR)
|
||||
return error;
|
||||
inode_lock_nested(dir, I_MUTEX_PARENT);
|
||||
// XXX: should've been
|
||||
// mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
// if (error == -EINTR)
|
||||
// return error;
|
||||
|
||||
dentry = lookup_one_len(name, parent->dentry, namelen);
|
||||
error = PTR_ERR(dentry);
|
||||
@ -2366,9 +2368,11 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
||||
goto out;
|
||||
|
||||
|
||||
err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
if (err == -EINTR)
|
||||
goto out_drop_write;
|
||||
inode_lock_nested(dir, I_MUTEX_PARENT);
|
||||
// XXX: should've been
|
||||
// err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
// if (err == -EINTR)
|
||||
// goto out_drop_write;
|
||||
dentry = lookup_one_len(vol_args->name, parent, namelen);
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
@ -2558,7 +2562,7 @@ out_dput:
|
||||
dput(dentry);
|
||||
out_unlock_dir:
|
||||
inode_unlock(dir);
|
||||
out_drop_write:
|
||||
//out_drop_write:
|
||||
mnt_drop_write_file(file);
|
||||
out:
|
||||
kfree(vol_args);
|
||||
|
@ -4988,7 +4988,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
|
||||
goto out;
|
||||
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb)
|
||||
if (!parent || d_really_is_negative(parent) || sb != parent->d_sb)
|
||||
goto out;
|
||||
inode = d_inode(parent);
|
||||
}
|
||||
@ -5009,7 +5009,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb)
|
||||
if (!parent || d_really_is_negative(parent) || sb != parent->d_sb)
|
||||
break;
|
||||
|
||||
if (IS_ROOT(parent))
|
||||
@ -5422,7 +5422,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb)
|
||||
if (!parent || d_really_is_negative(parent) || sb != parent->d_sb)
|
||||
break;
|
||||
|
||||
inode = d_inode(parent);
|
||||
|
@ -369,11 +369,9 @@ err:
|
||||
}
|
||||
|
||||
static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
name = xattr_full_name(handler, name);
|
||||
return __btrfs_getxattr(inode, name, buffer, size);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ static inline void ceph_set_cached_acl(struct inode *inode,
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0))
|
||||
set_cached_acl(inode, type, acl);
|
||||
else
|
||||
forget_cached_acl(inode, type);
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
}
|
||||
|
||||
|
@ -795,7 +795,7 @@ extern int ceph_setxattr(struct dentry *, const char *, const void *,
|
||||
int __ceph_setxattr(struct dentry *, const char *, const void *, size_t, int);
|
||||
ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t);
|
||||
int __ceph_removexattr(struct dentry *, const char *);
|
||||
extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
extern ssize_t ceph_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
|
||||
extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
|
||||
extern int ceph_removexattr(struct dentry *, const char *);
|
||||
extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
|
||||
|
@ -804,13 +804,13 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
|
||||
size_t size)
|
||||
ssize_t ceph_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||
return generic_getxattr(dentry, name, value, size);
|
||||
return generic_getxattr(dentry, inode, name, value, size);
|
||||
|
||||
return __ceph_getxattr(d_inode(dentry), name, value, size);
|
||||
return __ceph_getxattr(inode, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
|
||||
|
@ -302,7 +302,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
if (full_path == NULL)
|
||||
goto cdda_exit;
|
||||
|
||||
cifs_sb = CIFS_SB(d_inode(mntpt)->i_sb);
|
||||
cifs_sb = CIFS_SB(mntpt->d_sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
mnt = ERR_CAST(tlink);
|
||||
|
@ -1083,7 +1083,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||
};
|
||||
|
||||
const struct file_operations cifs_dir_ops = {
|
||||
.iterate = cifs_readdir,
|
||||
.iterate_shared = cifs_readdir,
|
||||
.release = cifs_closedir,
|
||||
.read = generic_read_dir,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
|
@ -123,7 +123,7 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
|
||||
extern int cifs_removexattr(struct dentry *, const char *);
|
||||
extern int cifs_setxattr(struct dentry *, const char *, const void *,
|
||||
size_t, int);
|
||||
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
extern ssize_t cifs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
|
||||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
#ifdef CONFIG_CIFS_NFSD_EXPORT
|
||||
|
@ -2418,8 +2418,7 @@ cifs_setattr_exit:
|
||||
int
|
||||
cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
{
|
||||
struct inode *inode = d_inode(direntry);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
||||
struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
|
||||
|
||||
if (pTcon->unix_ext)
|
||||
|
@ -78,20 +78,34 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
|
||||
{
|
||||
struct dentry *dentry, *alias;
|
||||
struct inode *inode;
|
||||
struct super_block *sb = d_inode(parent)->i_sb;
|
||||
struct super_block *sb = parent->d_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
||||
|
||||
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
|
||||
|
||||
dentry = d_hash_and_lookup(parent, name);
|
||||
if (!dentry) {
|
||||
/*
|
||||
* If we know that the inode will need to be revalidated
|
||||
* immediately, then don't create a new dentry for it.
|
||||
* We'll end up doing an on the wire call either way and
|
||||
* this spares us an invalidation.
|
||||
*/
|
||||
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
|
||||
return;
|
||||
retry:
|
||||
dentry = d_alloc_parallel(parent, name, &wq);
|
||||
}
|
||||
if (IS_ERR(dentry))
|
||||
return;
|
||||
|
||||
if (dentry) {
|
||||
if (!d_in_lookup(dentry)) {
|
||||
inode = d_inode(dentry);
|
||||
if (inode) {
|
||||
if (d_mountpoint(dentry))
|
||||
goto out;
|
||||
if (d_mountpoint(dentry)) {
|
||||
dput(dentry);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If we're generating inode numbers, then we don't
|
||||
* want to clobber the existing one with the one that
|
||||
@ -106,33 +120,22 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
|
||||
(inode->i_mode & S_IFMT) ==
|
||||
(fattr->cf_mode & S_IFMT)) {
|
||||
cifs_fattr_to_inode(inode, fattr);
|
||||
goto out;
|
||||
dput(dentry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
d_invalidate(dentry);
|
||||
dput(dentry);
|
||||
goto retry;
|
||||
} else {
|
||||
inode = cifs_iget(sb, fattr);
|
||||
if (!inode)
|
||||
inode = ERR_PTR(-ENOMEM);
|
||||
alias = d_splice_alias(inode, dentry);
|
||||
d_lookup_done(dentry);
|
||||
if (alias && !IS_ERR(alias))
|
||||
dput(alias);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we know that the inode will need to be revalidated immediately,
|
||||
* then don't create a new dentry for it. We'll end up doing an on
|
||||
* the wire call either way and this spares us an invalidation.
|
||||
*/
|
||||
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
|
||||
return;
|
||||
|
||||
dentry = d_alloc(parent, name);
|
||||
if (!dentry)
|
||||
return;
|
||||
|
||||
inode = cifs_iget(sb, fattr);
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
alias = d_splice_alias(inode, dentry);
|
||||
if (alias && !IS_ERR(alias))
|
||||
dput(alias);
|
||||
out:
|
||||
dput(dentry);
|
||||
}
|
||||
|
||||
|
@ -42,21 +42,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
|
||||
int rc = -EOPNOTSUPP;
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct super_block *sb;
|
||||
char *full_path = NULL;
|
||||
|
||||
if (direntry == NULL)
|
||||
return -EIO;
|
||||
if (d_really_is_negative(direntry))
|
||||
return -EIO;
|
||||
sb = d_inode(direntry)->i_sb;
|
||||
if (sb == NULL)
|
||||
return -EIO;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@ -103,21 +93,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
|
||||
int rc = -EOPNOTSUPP;
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct super_block *sb = direntry->d_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct super_block *sb;
|
||||
char *full_path;
|
||||
|
||||
if (direntry == NULL)
|
||||
return -EIO;
|
||||
if (d_really_is_negative(direntry))
|
||||
return -EIO;
|
||||
sb = d_inode(direntry)->i_sb;
|
||||
if (sb == NULL)
|
||||
return -EIO;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@ -232,27 +213,18 @@ set_ea_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
||||
void *ea_value, size_t buf_size)
|
||||
ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode,
|
||||
const char *ea_name, void *ea_value, size_t buf_size)
|
||||
{
|
||||
ssize_t rc = -EOPNOTSUPP;
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct super_block *sb = direntry->d_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct super_block *sb;
|
||||
char *full_path;
|
||||
|
||||
if (direntry == NULL)
|
||||
return -EIO;
|
||||
if (d_really_is_negative(direntry))
|
||||
return -EIO;
|
||||
sb = d_inode(direntry)->i_sb;
|
||||
if (sb == NULL)
|
||||
return -EIO;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@ -324,7 +296,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
||||
goto get_ea_exit; /* rc already EOPNOTSUPP */
|
||||
|
||||
pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
|
||||
d_inode(direntry), full_path, &acllen);
|
||||
inode, full_path, &acllen);
|
||||
if (IS_ERR(pacl)) {
|
||||
rc = PTR_ERR(pacl);
|
||||
cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
|
||||
@ -374,21 +346,11 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
|
||||
ssize_t rc = -EOPNOTSUPP;
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct super_block *sb;
|
||||
char *full_path;
|
||||
|
||||
if (direntry == NULL)
|
||||
return -EIO;
|
||||
if (d_really_is_negative(direntry))
|
||||
return -EIO;
|
||||
sb = d_inode(direntry)->i_sb;
|
||||
if (sb == NULL)
|
||||
return -EIO;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
@ -424,16 +424,22 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
|
||||
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
|
||||
host_file = cfi->cfi_container;
|
||||
|
||||
if (host_file->f_op->iterate) {
|
||||
if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
|
||||
struct inode *host_inode = file_inode(host_file);
|
||||
|
||||
inode_lock(host_inode);
|
||||
ret = -ENOENT;
|
||||
if (!IS_DEADDIR(host_inode)) {
|
||||
ret = host_file->f_op->iterate(host_file, ctx);
|
||||
file_accessed(host_file);
|
||||
if (host_file->f_op->iterate_shared) {
|
||||
inode_lock_shared(host_inode);
|
||||
ret = host_file->f_op->iterate_shared(host_file, ctx);
|
||||
file_accessed(host_file);
|
||||
inode_unlock_shared(host_inode);
|
||||
} else {
|
||||
inode_lock(host_inode);
|
||||
ret = host_file->f_op->iterate(host_file, ctx);
|
||||
file_accessed(host_file);
|
||||
inode_unlock(host_inode);
|
||||
}
|
||||
}
|
||||
inode_unlock(host_inode);
|
||||
return ret;
|
||||
}
|
||||
/* Venus: we must read Venus dirents from a file */
|
||||
|
12
fs/compat.c
12
fs/compat.c
@ -884,7 +884,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
|
||||
struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
|
||||
{
|
||||
int error;
|
||||
struct fd f = fdget(fd);
|
||||
struct fd f = fdget_pos(fd);
|
||||
struct compat_readdir_callback buf = {
|
||||
.ctx.actor = compat_fillonedir,
|
||||
.dirent = dirent
|
||||
@ -897,7 +897,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
fdput(f);
|
||||
fdput_pos(f);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -975,7 +975,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
return -EFAULT;
|
||||
|
||||
f = fdget(fd);
|
||||
f = fdget_pos(fd);
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
@ -989,7 +989,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
||||
else
|
||||
error = count - buf.count;
|
||||
}
|
||||
fdput(f);
|
||||
fdput_pos(f);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1062,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
return -EFAULT;
|
||||
|
||||
f = fdget(fd);
|
||||
f = fdget_pos(fd);
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
@ -1077,7 +1077,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
||||
else
|
||||
error = count - buf.count;
|
||||
}
|
||||
fdput(f);
|
||||
fdput_pos(f);
|
||||
return error;
|
||||
}
|
||||
#endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
|
||||
|
@ -494,7 +494,7 @@ out:
|
||||
* If there is an error, the caller will reset the flags via
|
||||
* configfs_detach_rollback().
|
||||
*/
|
||||
static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex)
|
||||
static int configfs_detach_prep(struct dentry *dentry, struct dentry **wait)
|
||||
{
|
||||
struct configfs_dirent *parent_sd = dentry->d_fsdata;
|
||||
struct configfs_dirent *sd;
|
||||
@ -515,8 +515,8 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex
|
||||
if (sd->s_type & CONFIGFS_USET_DEFAULT) {
|
||||
/* Abort if racing with mkdir() */
|
||||
if (sd->s_type & CONFIGFS_USET_IN_MKDIR) {
|
||||
if (wait_mutex)
|
||||
*wait_mutex = &d_inode(sd->s_dentry)->i_mutex;
|
||||
if (wait)
|
||||
*wait= dget(sd->s_dentry);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
@ -524,7 +524,7 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex
|
||||
* Yup, recursive. If there's a problem, blame
|
||||
* deep nesting of default_groups
|
||||
*/
|
||||
ret = configfs_detach_prep(sd->s_dentry, wait_mutex);
|
||||
ret = configfs_detach_prep(sd->s_dentry, wait);
|
||||
if (!ret)
|
||||
continue;
|
||||
} else
|
||||
@ -1458,7 +1458,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
* the new link is temporarily attached
|
||||
*/
|
||||
do {
|
||||
struct mutex *wait_mutex;
|
||||
struct dentry *wait;
|
||||
|
||||
mutex_lock(&configfs_symlink_mutex);
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
@ -1469,7 +1469,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
*/
|
||||
ret = sd->s_dependent_count ? -EBUSY : 0;
|
||||
if (!ret) {
|
||||
ret = configfs_detach_prep(dentry, &wait_mutex);
|
||||
ret = configfs_detach_prep(dentry, &wait);
|
||||
if (ret)
|
||||
configfs_detach_rollback(dentry);
|
||||
}
|
||||
@ -1483,8 +1483,9 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
}
|
||||
|
||||
/* Wait until the racing operation terminates */
|
||||
mutex_lock(wait_mutex);
|
||||
mutex_unlock(wait_mutex);
|
||||
inode_lock(d_inode(wait));
|
||||
inode_unlock(d_inode(wait));
|
||||
dput(wait);
|
||||
}
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
@ -1632,11 +1633,9 @@ static int configfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
if (ctx->pos == 2) {
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
if (ctx->pos == 2)
|
||||
list_move(q, &parent_sd->s_children);
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
}
|
||||
for (p = q->next; p != &parent_sd->s_children; p = p->next) {
|
||||
struct configfs_dirent *next;
|
||||
const char *name;
|
||||
@ -1647,9 +1646,6 @@ static int configfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
if (!next->s_element)
|
||||
continue;
|
||||
|
||||
name = configfs_get_name(next);
|
||||
len = strlen(name);
|
||||
|
||||
/*
|
||||
* We'll have a dentry and an inode for
|
||||
* PINNED items and for open attribute
|
||||
@ -1663,7 +1659,6 @@ static int configfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
* they close it. Beyond that, we don't
|
||||
* care.
|
||||
*/
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
dentry = next->s_dentry;
|
||||
if (dentry)
|
||||
inode = d_inode(dentry);
|
||||
@ -1673,15 +1668,18 @@ static int configfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
if (!inode)
|
||||
ino = iunique(sb, 2);
|
||||
|
||||
name = configfs_get_name(next);
|
||||
len = strlen(name);
|
||||
|
||||
if (!dir_emit(ctx, name, len, ino, dt_type(next)))
|
||||
return 0;
|
||||
|
||||
spin_lock(&configfs_dirent_lock);
|
||||
list_move(q, p);
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
p = q;
|
||||
ctx->pos++;
|
||||
}
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1689,7 +1687,6 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct dentry * dentry = file->f_path.dentry;
|
||||
|
||||
inode_lock(d_inode(dentry));
|
||||
switch (whence) {
|
||||
case 1:
|
||||
offset += file->f_pos;
|
||||
@ -1697,7 +1694,6 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
|
||||
if (offset >= 0)
|
||||
break;
|
||||
default:
|
||||
inode_unlock(d_inode(dentry));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (offset != file->f_pos) {
|
||||
@ -1723,7 +1719,6 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
|
||||
spin_unlock(&configfs_dirent_lock);
|
||||
}
|
||||
}
|
||||
inode_unlock(d_inode(dentry));
|
||||
return offset;
|
||||
}
|
||||
|
||||
@ -1732,7 +1727,7 @@ const struct file_operations configfs_dir_operations = {
|
||||
.release = configfs_dir_close,
|
||||
.llseek = configfs_dir_lseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = configfs_readdir,
|
||||
.iterate_shared = configfs_readdir,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -156,7 +156,7 @@ static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
|
||||
|
||||
if (depth > 0) {
|
||||
if (depth <= ARRAY_SIZE(default_group_class)) {
|
||||
lockdep_set_class(&inode->i_mutex,
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&default_group_class[depth - 1]);
|
||||
} else {
|
||||
/*
|
||||
|
@ -561,7 +561,7 @@ static const struct address_space_operations cramfs_aops = {
|
||||
static const struct file_operations cramfs_directory_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = cramfs_readdir,
|
||||
.iterate_shared = cramfs_readdir,
|
||||
};
|
||||
|
||||
static const struct inode_operations cramfs_dir_inode_operations = {
|
||||
|
271
fs/dcache.c
271
fs/dcache.c
@ -111,6 +111,17 @@ static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
|
||||
return dentry_hashtable + hash_32(hash, d_hash_shift);
|
||||
}
|
||||
|
||||
#define IN_LOOKUP_SHIFT 10
|
||||
static struct hlist_bl_head in_lookup_hashtable[1 << IN_LOOKUP_SHIFT];
|
||||
|
||||
static inline struct hlist_bl_head *in_lookup_hash(const struct dentry *parent,
|
||||
unsigned int hash)
|
||||
{
|
||||
hash += (unsigned long) parent / L1_CACHE_BYTES;
|
||||
return in_lookup_hashtable + hash_32(hash, IN_LOOKUP_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
/* Statistics gathering. */
|
||||
struct dentry_stat_t dentry_stat = {
|
||||
.age_limit = 45,
|
||||
@ -761,6 +772,8 @@ repeat:
|
||||
/* Slow case: now with the dentry lock held */
|
||||
rcu_read_unlock();
|
||||
|
||||
WARN_ON(d_in_lookup(dentry));
|
||||
|
||||
/* Unreachable? Get rid of it */
|
||||
if (unlikely(d_unhashed(dentry)))
|
||||
goto kill_it;
|
||||
@ -1746,6 +1759,7 @@ type_determined:
|
||||
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
unsigned add_flags = d_flags_for_inode(inode);
|
||||
WARN_ON(d_in_lookup(dentry));
|
||||
|
||||
spin_lock(&dentry->d_lock);
|
||||
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
|
||||
@ -1775,11 +1789,11 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
|
||||
{
|
||||
BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
|
||||
if (inode) {
|
||||
security_d_instantiate(entry, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
__d_instantiate(entry, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
security_d_instantiate(entry, inode);
|
||||
}
|
||||
EXPORT_SYMBOL(d_instantiate);
|
||||
|
||||
@ -1796,6 +1810,7 @@ int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
|
||||
|
||||
security_d_instantiate(entry, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
@ -1804,7 +1819,6 @@ int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
|
||||
}
|
||||
__d_instantiate(entry, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
security_d_instantiate(entry, inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1878,6 +1892,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
|
||||
goto out_iput;
|
||||
}
|
||||
|
||||
security_d_instantiate(tmp, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
res = __d_find_any_alias(inode);
|
||||
if (res) {
|
||||
@ -1900,13 +1915,10 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
|
||||
hlist_bl_unlock(&tmp->d_sb->s_anon);
|
||||
spin_unlock(&tmp->d_lock);
|
||||
spin_unlock(&inode->i_lock);
|
||||
security_d_instantiate(tmp, inode);
|
||||
|
||||
return tmp;
|
||||
|
||||
out_iput:
|
||||
if (res && !IS_ERR(res))
|
||||
security_d_instantiate(res, inode);
|
||||
iput(inode);
|
||||
return res;
|
||||
}
|
||||
@ -1975,28 +1987,36 @@ EXPORT_SYMBOL(d_obtain_root);
|
||||
struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
|
||||
struct qstr *name)
|
||||
{
|
||||
struct dentry *found;
|
||||
struct dentry *new;
|
||||
struct dentry *found, *res;
|
||||
|
||||
/*
|
||||
* First check if a dentry matching the name already exists,
|
||||
* if not go ahead and create it now.
|
||||
*/
|
||||
found = d_hash_and_lookup(dentry->d_parent, name);
|
||||
if (!found) {
|
||||
new = d_alloc(dentry->d_parent, name);
|
||||
if (!new) {
|
||||
found = ERR_PTR(-ENOMEM);
|
||||
} else {
|
||||
found = d_splice_alias(inode, new);
|
||||
if (found) {
|
||||
dput(new);
|
||||
return found;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
if (found) {
|
||||
iput(inode);
|
||||
return found;
|
||||
}
|
||||
if (d_in_lookup(dentry)) {
|
||||
found = d_alloc_parallel(dentry->d_parent, name,
|
||||
dentry->d_wait);
|
||||
if (IS_ERR(found) || !d_in_lookup(found)) {
|
||||
iput(inode);
|
||||
return found;
|
||||
}
|
||||
} else {
|
||||
found = d_alloc(dentry->d_parent, name);
|
||||
if (!found) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
}
|
||||
res = d_splice_alias(inode, found);
|
||||
if (res) {
|
||||
dput(found);
|
||||
return res;
|
||||
}
|
||||
iput(inode);
|
||||
return found;
|
||||
}
|
||||
EXPORT_SYMBOL(d_add_ci);
|
||||
@ -2363,17 +2383,194 @@ void d_rehash(struct dentry * entry)
|
||||
}
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
|
||||
static inline unsigned start_dir_add(struct inode *dir)
|
||||
{
|
||||
|
||||
for (;;) {
|
||||
unsigned n = dir->i_dir_seq;
|
||||
if (!(n & 1) && cmpxchg(&dir->i_dir_seq, n, n + 1) == n)
|
||||
return n;
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void end_dir_add(struct inode *dir, unsigned n)
|
||||
{
|
||||
smp_store_release(&dir->i_dir_seq, n + 2);
|
||||
}
|
||||
|
||||
static void d_wait_lookup(struct dentry *dentry)
|
||||
{
|
||||
if (d_in_lookup(dentry)) {
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
add_wait_queue(dentry->d_wait, &wait);
|
||||
do {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
schedule();
|
||||
spin_lock(&dentry->d_lock);
|
||||
} while (d_in_lookup(dentry));
|
||||
}
|
||||
}
|
||||
|
||||
struct dentry *d_alloc_parallel(struct dentry *parent,
|
||||
const struct qstr *name,
|
||||
wait_queue_head_t *wq)
|
||||
{
|
||||
unsigned int len = name->len;
|
||||
unsigned int hash = name->hash;
|
||||
const unsigned char *str = name->name;
|
||||
struct hlist_bl_head *b = in_lookup_hash(parent, hash);
|
||||
struct hlist_bl_node *node;
|
||||
struct dentry *new = d_alloc(parent, name);
|
||||
struct dentry *dentry;
|
||||
unsigned seq, r_seq, d_seq;
|
||||
|
||||
if (unlikely(!new))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
retry:
|
||||
rcu_read_lock();
|
||||
seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1;
|
||||
r_seq = read_seqbegin(&rename_lock);
|
||||
dentry = __d_lookup_rcu(parent, name, &d_seq);
|
||||
if (unlikely(dentry)) {
|
||||
if (!lockref_get_not_dead(&dentry->d_lockref)) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (read_seqcount_retry(&dentry->d_seq, d_seq)) {
|
||||
rcu_read_unlock();
|
||||
dput(dentry);
|
||||
goto retry;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
dput(new);
|
||||
return dentry;
|
||||
}
|
||||
if (unlikely(read_seqretry(&rename_lock, r_seq))) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
hlist_bl_lock(b);
|
||||
if (unlikely(parent->d_inode->i_dir_seq != seq)) {
|
||||
hlist_bl_unlock(b);
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
/*
|
||||
* No changes for the parent since the beginning of d_lookup().
|
||||
* Since all removals from the chain happen with hlist_bl_lock(),
|
||||
* any potential in-lookup matches are going to stay here until
|
||||
* we unlock the chain. All fields are stable in everything
|
||||
* we encounter.
|
||||
*/
|
||||
hlist_bl_for_each_entry(dentry, node, b, d_u.d_in_lookup_hash) {
|
||||
if (dentry->d_name.hash != hash)
|
||||
continue;
|
||||
if (dentry->d_parent != parent)
|
||||
continue;
|
||||
if (d_unhashed(dentry))
|
||||
continue;
|
||||
if (parent->d_flags & DCACHE_OP_COMPARE) {
|
||||
int tlen = dentry->d_name.len;
|
||||
const char *tname = dentry->d_name.name;
|
||||
if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
|
||||
continue;
|
||||
} else {
|
||||
if (dentry->d_name.len != len)
|
||||
continue;
|
||||
if (dentry_cmp(dentry, str, len))
|
||||
continue;
|
||||
}
|
||||
dget(dentry);
|
||||
hlist_bl_unlock(b);
|
||||
/* somebody is doing lookup for it right now; wait for it */
|
||||
spin_lock(&dentry->d_lock);
|
||||
d_wait_lookup(dentry);
|
||||
/*
|
||||
* it's not in-lookup anymore; in principle we should repeat
|
||||
* everything from dcache lookup, but it's likely to be what
|
||||
* d_lookup() would've found anyway. If it is, just return it;
|
||||
* otherwise we really have to repeat the whole thing.
|
||||
*/
|
||||
if (unlikely(dentry->d_name.hash != hash))
|
||||
goto mismatch;
|
||||
if (unlikely(dentry->d_parent != parent))
|
||||
goto mismatch;
|
||||
if (unlikely(d_unhashed(dentry)))
|
||||
goto mismatch;
|
||||
if (parent->d_flags & DCACHE_OP_COMPARE) {
|
||||
int tlen = dentry->d_name.len;
|
||||
const char *tname = dentry->d_name.name;
|
||||
if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
|
||||
goto mismatch;
|
||||
} else {
|
||||
if (unlikely(dentry->d_name.len != len))
|
||||
goto mismatch;
|
||||
if (unlikely(dentry_cmp(dentry, str, len)))
|
||||
goto mismatch;
|
||||
}
|
||||
/* OK, it *is* a hashed match; return it */
|
||||
spin_unlock(&dentry->d_lock);
|
||||
dput(new);
|
||||
return dentry;
|
||||
}
|
||||
/* we can't take ->d_lock here; it's OK, though. */
|
||||
new->d_flags |= DCACHE_PAR_LOOKUP;
|
||||
new->d_wait = wq;
|
||||
hlist_bl_add_head_rcu(&new->d_u.d_in_lookup_hash, b);
|
||||
hlist_bl_unlock(b);
|
||||
return new;
|
||||
mismatch:
|
||||
spin_unlock(&dentry->d_lock);
|
||||
dput(dentry);
|
||||
goto retry;
|
||||
}
|
||||
EXPORT_SYMBOL(d_alloc_parallel);
|
||||
|
||||
void __d_lookup_done(struct dentry *dentry)
|
||||
{
|
||||
struct hlist_bl_head *b = in_lookup_hash(dentry->d_parent,
|
||||
dentry->d_name.hash);
|
||||
hlist_bl_lock(b);
|
||||
dentry->d_flags &= ~DCACHE_PAR_LOOKUP;
|
||||
__hlist_bl_del(&dentry->d_u.d_in_lookup_hash);
|
||||
wake_up_all(dentry->d_wait);
|
||||
dentry->d_wait = NULL;
|
||||
hlist_bl_unlock(b);
|
||||
INIT_HLIST_NODE(&dentry->d_u.d_alias);
|
||||
INIT_LIST_HEAD(&dentry->d_lru);
|
||||
}
|
||||
EXPORT_SYMBOL(__d_lookup_done);
|
||||
|
||||
/* inode->i_lock held if inode is non-NULL */
|
||||
|
||||
static inline void __d_add(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
if (inode) {
|
||||
__d_instantiate(dentry, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
struct inode *dir = NULL;
|
||||
unsigned n;
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (unlikely(d_in_lookup(dentry))) {
|
||||
dir = dentry->d_parent->d_inode;
|
||||
n = start_dir_add(dir);
|
||||
__d_lookup_done(dentry);
|
||||
}
|
||||
security_d_instantiate(dentry, inode);
|
||||
d_rehash(dentry);
|
||||
if (inode) {
|
||||
unsigned add_flags = d_flags_for_inode(inode);
|
||||
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
|
||||
raw_write_seqcount_begin(&dentry->d_seq);
|
||||
__d_set_inode_and_type(dentry, inode, add_flags);
|
||||
raw_write_seqcount_end(&dentry->d_seq);
|
||||
__fsnotify_d_instantiate(dentry);
|
||||
}
|
||||
_d_rehash(dentry);
|
||||
if (dir)
|
||||
end_dir_add(dir, n);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
if (inode)
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2387,8 +2584,10 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
|
||||
|
||||
void d_add(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
if (inode)
|
||||
if (inode) {
|
||||
security_d_instantiate(entry, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
}
|
||||
__d_add(entry, inode);
|
||||
}
|
||||
EXPORT_SYMBOL(d_add);
|
||||
@ -2598,6 +2797,8 @@ static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
|
||||
static void __d_move(struct dentry *dentry, struct dentry *target,
|
||||
bool exchange)
|
||||
{
|
||||
struct inode *dir = NULL;
|
||||
unsigned n;
|
||||
if (!dentry->d_inode)
|
||||
printk(KERN_WARNING "VFS: moving negative dcache entry\n");
|
||||
|
||||
@ -2605,6 +2806,11 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
||||
BUG_ON(d_ancestor(target, dentry));
|
||||
|
||||
dentry_lock_for_move(dentry, target);
|
||||
if (unlikely(d_in_lookup(target))) {
|
||||
dir = target->d_parent->d_inode;
|
||||
n = start_dir_add(dir);
|
||||
__d_lookup_done(target);
|
||||
}
|
||||
|
||||
write_seqcount_begin(&dentry->d_seq);
|
||||
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
|
||||
@ -2654,6 +2860,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
||||
write_seqcount_end(&target->d_seq);
|
||||
write_seqcount_end(&dentry->d_seq);
|
||||
|
||||
if (dir)
|
||||
end_dir_add(dir, n);
|
||||
dentry_unlock_for_move(dentry, target);
|
||||
}
|
||||
|
||||
@ -2724,7 +2932,8 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
|
||||
static int __d_unalias(struct inode *inode,
|
||||
struct dentry *dentry, struct dentry *alias)
|
||||
{
|
||||
struct mutex *m1 = NULL, *m2 = NULL;
|
||||
struct mutex *m1 = NULL;
|
||||
struct rw_semaphore *m2 = NULL;
|
||||
int ret = -ESTALE;
|
||||
|
||||
/* If alias and dentry share a parent, then no extra locks required */
|
||||
@ -2735,15 +2944,15 @@ static int __d_unalias(struct inode *inode,
|
||||
if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
|
||||
goto out_err;
|
||||
m1 = &dentry->d_sb->s_vfs_rename_mutex;
|
||||
if (!inode_trylock(alias->d_parent->d_inode))
|
||||
if (!inode_trylock_shared(alias->d_parent->d_inode))
|
||||
goto out_err;
|
||||
m2 = &alias->d_parent->d_inode->i_mutex;
|
||||
m2 = &alias->d_parent->d_inode->i_rwsem;
|
||||
out_unalias:
|
||||
__d_move(alias, dentry, false);
|
||||
ret = 0;
|
||||
out_err:
|
||||
if (m2)
|
||||
mutex_unlock(m2);
|
||||
up_read(m2);
|
||||
if (m1)
|
||||
mutex_unlock(m1);
|
||||
return ret;
|
||||
@ -2782,6 +2991,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
security_d_instantiate(dentry, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
struct dentry *new = __d_find_any_alias(inode);
|
||||
@ -2809,7 +3019,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
} else {
|
||||
__d_move(new, dentry, false);
|
||||
write_sequnlock(&rename_lock);
|
||||
security_d_instantiate(new, inode);
|
||||
}
|
||||
iput(inode);
|
||||
return new;
|
||||
|
@ -1369,7 +1369,9 @@ int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)
|
||||
ssize_t size;
|
||||
int rc = 0;
|
||||
|
||||
size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
|
||||
size = ecryptfs_getxattr_lower(lower_dentry,
|
||||
ecryptfs_inode_to_lower(ecryptfs_inode),
|
||||
ECRYPTFS_XATTR_NAME,
|
||||
page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
|
||||
if (size < 0) {
|
||||
if (unlikely(ecryptfs_verbosity > 0))
|
||||
@ -1391,6 +1393,7 @@ int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry,
|
||||
int rc;
|
||||
|
||||
rc = ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry),
|
||||
ecryptfs_inode_to_lower(inode),
|
||||
ECRYPTFS_XATTR_NAME, file_size,
|
||||
ECRYPTFS_SIZE_AND_MARKER_BYTES);
|
||||
if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
|
||||
|
@ -606,8 +606,8 @@ ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
|
||||
unsigned char *src, struct dentry *ecryptfs_dentry);
|
||||
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
|
||||
ssize_t
|
||||
ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
|
||||
void *value, size_t size);
|
||||
ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,
|
||||
const char *name, void *value, size_t size);
|
||||
int
|
||||
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
|
@ -383,7 +383,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
#endif
|
||||
|
||||
const struct file_operations ecryptfs_dir_fops = {
|
||||
.iterate = ecryptfs_readdir,
|
||||
.iterate_shared = ecryptfs_readdir,
|
||||
.read = generic_read_dir,
|
||||
.unlocked_ioctl = ecryptfs_unlocked_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
@ -1036,29 +1036,30 @@ out:
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
|
||||
void *value, size_t size)
|
||||
ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!d_inode(lower_dentry)->i_op->getxattr) {
|
||||
if (!lower_inode->i_op->getxattr) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
inode_lock(d_inode(lower_dentry));
|
||||
rc = d_inode(lower_dentry)->i_op->getxattr(lower_dentry, name, value,
|
||||
size);
|
||||
inode_unlock(d_inode(lower_dentry));
|
||||
inode_lock(lower_inode);
|
||||
rc = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
|
||||
name, value, size);
|
||||
inode_unlock(lower_inode);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
|
||||
size_t size)
|
||||
ecryptfs_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name,
|
||||
value, size);
|
||||
return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry),
|
||||
ecryptfs_inode_to_lower(inode),
|
||||
name, value, size);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
@ -436,7 +436,8 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
|
||||
goto out;
|
||||
}
|
||||
inode_lock(lower_inode);
|
||||
size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME,
|
||||
size = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
|
||||
ECRYPTFS_XATTR_NAME,
|
||||
xattr_virt, PAGE_SIZE);
|
||||
if (size < 0)
|
||||
size = 8;
|
||||
|
@ -12,7 +12,7 @@ static int efs_readdir(struct file *, struct dir_context *);
|
||||
const struct file_operations efs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = efs_readdir,
|
||||
.iterate_shared = efs_readdir,
|
||||
};
|
||||
|
||||
const struct inode_operations efs_dir_inode_operations = {
|
||||
@ -100,4 +100,3 @@ static int efs_readdir(struct file *file, struct dir_context *ctx)
|
||||
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ struct dentry *efs_get_parent(struct dentry *child)
|
||||
|
||||
ino = efs_find_entry(d_inode(child), "..", 2);
|
||||
if (ino)
|
||||
parent = d_obtain_alias(efs_iget(d_inode(child)->i_sb, ino));
|
||||
parent = d_obtain_alias(efs_iget(child->d_sb, ino));
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void exofs_check_page(struct page *page)
|
||||
static bool exofs_check_page(struct page *page)
|
||||
{
|
||||
struct inode *dir = page->mapping->host;
|
||||
unsigned chunk_size = exofs_chunk_size(dir);
|
||||
@ -114,7 +114,7 @@ static void exofs_check_page(struct page *page)
|
||||
goto Eend;
|
||||
out:
|
||||
SetPageChecked(page);
|
||||
return;
|
||||
return true;
|
||||
|
||||
Ebadsize:
|
||||
EXOFS_ERR("ERROR [exofs_check_page]: "
|
||||
@ -150,8 +150,8 @@ Eend:
|
||||
dir->i_ino, (page->index<<PAGE_SHIFT)+offs,
|
||||
_LLU(le64_to_cpu(p->inode_no)));
|
||||
fail:
|
||||
SetPageChecked(page);
|
||||
SetPageError(page);
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct page *exofs_get_page(struct inode *dir, unsigned long n)
|
||||
@ -161,10 +161,10 @@ static struct page *exofs_get_page(struct inode *dir, unsigned long n)
|
||||
|
||||
if (!IS_ERR(page)) {
|
||||
kmap(page);
|
||||
if (!PageChecked(page))
|
||||
exofs_check_page(page);
|
||||
if (PageError(page))
|
||||
goto fail;
|
||||
if (unlikely(!PageChecked(page))) {
|
||||
if (PageError(page) || !exofs_check_page(page))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return page;
|
||||
|
||||
@ -657,5 +657,5 @@ not_empty:
|
||||
const struct file_operations exofs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = exofs_readdir,
|
||||
.iterate_shared = exofs_readdir,
|
||||
};
|
||||
|
@ -958,7 +958,7 @@ static struct dentry *exofs_get_parent(struct dentry *child)
|
||||
if (!ino)
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
return d_obtain_alias(exofs_iget(d_inode(child)->i_sb, ino));
|
||||
return d_obtain_alias(exofs_iget(child->d_sb, ino));
|
||||
}
|
||||
|
||||
static struct inode *exofs_nfs_get_inode(struct super_block *sb,
|
||||
|
@ -143,14 +143,18 @@ static struct dentry *reconnect_one(struct vfsmount *mnt,
|
||||
if (err)
|
||||
goto out_err;
|
||||
dprintk("%s: found name: %s\n", __func__, nbuf);
|
||||
inode_lock(parent->d_inode);
|
||||
tmp = lookup_one_len(nbuf, parent, strlen(nbuf));
|
||||
inode_unlock(parent->d_inode);
|
||||
tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf));
|
||||
if (IS_ERR(tmp)) {
|
||||
dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
|
||||
goto out_err;
|
||||
}
|
||||
if (tmp != dentry) {
|
||||
/*
|
||||
* Somebody has renamed it since exportfs_get_name();
|
||||
* great, since it could've only been renamed if it
|
||||
* got looked up and thus connected, and it would
|
||||
* remain connected afterwards. We are done.
|
||||
*/
|
||||
dput(tmp);
|
||||
goto out_reconnected;
|
||||
}
|
||||
@ -308,7 +312,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
|
||||
goto out;
|
||||
|
||||
error = -EINVAL;
|
||||
if (!file->f_op->iterate)
|
||||
if (!file->f_op->iterate && !file->f_op->iterate_shared)
|
||||
goto out_close;
|
||||
|
||||
buffer.sequence = 0;
|
||||
|
@ -172,9 +172,6 @@ ext2_get_acl(struct inode *inode, int type)
|
||||
acl = ERR_PTR(retval);
|
||||
kfree(value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ext2_check_page(struct page *page, int quiet)
|
||||
static bool ext2_check_page(struct page *page, int quiet)
|
||||
{
|
||||
struct inode *dir = page->mapping->host;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
@ -148,7 +148,7 @@ static void ext2_check_page(struct page *page, int quiet)
|
||||
goto Eend;
|
||||
out:
|
||||
SetPageChecked(page);
|
||||
return;
|
||||
return true;
|
||||
|
||||
/* Too bad, we had an error */
|
||||
|
||||
@ -190,8 +190,8 @@ Eend:
|
||||
(unsigned long) le32_to_cpu(p->inode));
|
||||
}
|
||||
fail:
|
||||
SetPageChecked(page);
|
||||
SetPageError(page);
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct page * ext2_get_page(struct inode *dir, unsigned long n,
|
||||
@ -201,10 +201,10 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n,
|
||||
struct page *page = read_mapping_page(mapping, n, NULL);
|
||||
if (!IS_ERR(page)) {
|
||||
kmap(page);
|
||||
if (!PageChecked(page))
|
||||
ext2_check_page(page, quiet);
|
||||
if (PageError(page))
|
||||
goto fail;
|
||||
if (unlikely(!PageChecked(page))) {
|
||||
if (PageError(page) || !ext2_check_page(page, quiet))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return page;
|
||||
|
||||
@ -716,7 +716,7 @@ not_empty:
|
||||
const struct file_operations ext2_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = ext2_readdir,
|
||||
.iterate_shared = ext2_readdir,
|
||||
.unlocked_ioctl = ext2_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ext2_compat_ioctl,
|
||||
|
@ -82,7 +82,7 @@ struct dentry *ext2_get_parent(struct dentry *child)
|
||||
unsigned long ino = ext2_inode_by_name(d_inode(child), &dotdot);
|
||||
if (!ino)
|
||||
return ERR_PTR(-ENOENT);
|
||||
return d_obtain_alias(ext2_iget(d_inode(child)->i_sb, ino));
|
||||
return d_obtain_alias(ext2_iget(child->d_sb, ino));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9,10 +9,10 @@
|
||||
|
||||
static int
|
||||
ext2_xattr_security_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name,
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_SECURITY, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ ext2_xattr_trusted_list(struct dentry *dentry)
|
||||
|
||||
static int
|
||||
ext2_xattr_trusted_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,12 @@ ext2_xattr_user_list(struct dentry *dentry)
|
||||
|
||||
static int
|
||||
ext2_xattr_user_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_USER,
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
|
@ -172,9 +172,6 @@ ext4_get_acl(struct inode *inode, int type)
|
||||
acl = ERR_PTR(retval);
|
||||
kfree(value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
||||
ctx->pos += ext4_rec_len_from_disk(de->rec_len,
|
||||
sb->s_blocksize);
|
||||
}
|
||||
if ((ctx->pos < inode->i_size) && !dir_relax(inode))
|
||||
if ((ctx->pos < inode->i_size) && !dir_relax_shared(inode))
|
||||
goto done;
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
@ -644,7 +644,7 @@ int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
|
||||
const struct file_operations ext4_dir_operations = {
|
||||
.llseek = ext4_dir_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = ext4_readdir,
|
||||
.iterate_shared = ext4_readdir,
|
||||
.unlocked_ioctl = ext4_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ext4_compat_ioctl,
|
||||
|
@ -1638,13 +1638,13 @@ struct dentry *ext4_get_parent(struct dentry *child)
|
||||
ino = le32_to_cpu(de->inode);
|
||||
brelse(bh);
|
||||
|
||||
if (!ext4_valid_inum(d_inode(child)->i_sb, ino)) {
|
||||
if (!ext4_valid_inum(child->d_sb, ino)) {
|
||||
EXT4_ERROR_INODE(d_inode(child),
|
||||
"bad parent inode number: %u", ino);
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
}
|
||||
|
||||
return d_obtain_alias(ext4_iget_normal(d_inode(child)->i_sb, ino));
|
||||
return d_obtain_alias(ext4_iget_normal(child->d_sb, ino));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -13,10 +13,10 @@
|
||||
|
||||
static int
|
||||
ext4_xattr_security_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY,
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,10 @@ ext4_xattr_trusted_list(struct dentry *dentry)
|
||||
|
||||
static int
|
||||
ext4_xattr_trusted_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED,
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,12 @@ ext4_xattr_user_list(struct dentry *dentry)
|
||||
|
||||
static int
|
||||
ext4_xattr_user_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_USER,
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
|
@ -190,9 +190,6 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
|
||||
acl = ERR_PTR(retval);
|
||||
kfree(value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -902,7 +902,7 @@ static int f2fs_dir_open(struct inode *inode, struct file *filp)
|
||||
const struct file_operations f2fs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = f2fs_readdir,
|
||||
.iterate_shared = f2fs_readdir,
|
||||
.fsync = f2fs_sync_file,
|
||||
.open = f2fs_dir_open,
|
||||
.unlocked_ioctl = f2fs_ioctl,
|
||||
|
@ -202,7 +202,7 @@ struct dentry *f2fs_get_parent(struct dentry *child)
|
||||
unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot);
|
||||
if (!ino)
|
||||
return ERR_PTR(-ENOENT);
|
||||
return d_obtain_alias(f2fs_iget(d_inode(child)->i_sb, ino));
|
||||
return d_obtain_alias(f2fs_iget(child->d_sb, ino));
|
||||
}
|
||||
|
||||
static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
|
@ -26,10 +26,10 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
|
||||
switch (handler->flags) {
|
||||
case F2FS_XATTR_INDEX_USER:
|
||||
@ -45,7 +45,7 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return f2fs_getxattr(d_inode(dentry), handler->flags, name,
|
||||
return f2fs_getxattr(inode, handler->flags, name,
|
||||
buffer, size, NULL);
|
||||
}
|
||||
|
||||
@ -86,11 +86,9 @@ static bool f2fs_xattr_trusted_list(struct dentry *dentry)
|
||||
}
|
||||
|
||||
static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
if (buffer)
|
||||
*((char *)buffer) = F2FS_I(inode)->i_advise;
|
||||
return sizeof(char);
|
||||
|
@ -769,7 +769,7 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *file,
|
||||
|
||||
buf.dirent = dirent;
|
||||
buf.result = 0;
|
||||
inode_lock(inode);
|
||||
inode_lock_shared(inode);
|
||||
buf.ctx.pos = file->f_pos;
|
||||
ret = -ENOENT;
|
||||
if (!IS_DEADDIR(inode)) {
|
||||
@ -777,7 +777,7 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *file,
|
||||
short_only, both ? &buf : NULL);
|
||||
file->f_pos = buf.ctx.pos;
|
||||
}
|
||||
inode_unlock(inode);
|
||||
inode_unlock_shared(inode);
|
||||
if (ret >= 0)
|
||||
ret = buf.result;
|
||||
return ret;
|
||||
@ -861,7 +861,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
|
||||
const struct file_operations fat_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = fat_readdir,
|
||||
.iterate_shared = fat_readdir,
|
||||
.unlocked_ioctl = fat_dir_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = fat_compat_dir_ioctl,
|
||||
|
@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd)
|
||||
return v;
|
||||
}
|
||||
|
||||
void __f_unlock_pos(struct file *f)
|
||||
{
|
||||
mutex_unlock(&f->f_pos_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* We only lock f_pos if we have threads or if the file might be
|
||||
* shared with another process. In both cases we'll have an elevated
|
||||
|
@ -58,7 +58,7 @@ const struct inode_operations vxfs_dir_inode_ops = {
|
||||
const struct file_operations vxfs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = vxfs_readdir,
|
||||
.iterate_shared = vxfs_readdir,
|
||||
};
|
||||
|
||||
static inline u_long
|
||||
|
105
fs/fuse/dir.c
105
fs/fuse/dir.c
@ -1162,7 +1162,6 @@ static int fuse_direntplus_link(struct file *file,
|
||||
struct fuse_direntplus *direntplus,
|
||||
u64 attr_version)
|
||||
{
|
||||
int err;
|
||||
struct fuse_entry_out *o = &direntplus->entry_out;
|
||||
struct fuse_dirent *dirent = &direntplus->dirent;
|
||||
struct dentry *parent = file->f_path.dentry;
|
||||
@ -1172,6 +1171,7 @@ static int fuse_direntplus_link(struct file *file,
|
||||
struct inode *dir = d_inode(parent);
|
||||
struct fuse_conn *fc;
|
||||
struct inode *inode;
|
||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
||||
|
||||
if (!o->nodeid) {
|
||||
/*
|
||||
@ -1204,65 +1204,61 @@ static int fuse_direntplus_link(struct file *file,
|
||||
|
||||
name.hash = full_name_hash(name.name, name.len);
|
||||
dentry = d_lookup(parent, &name);
|
||||
if (dentry) {
|
||||
if (!dentry) {
|
||||
retry:
|
||||
dentry = d_alloc_parallel(parent, &name, &wq);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
}
|
||||
if (!d_in_lookup(dentry)) {
|
||||
struct fuse_inode *fi;
|
||||
inode = d_inode(dentry);
|
||||
if (!inode) {
|
||||
d_drop(dentry);
|
||||
} else if (get_node_id(inode) != o->nodeid ||
|
||||
((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
|
||||
if (!inode ||
|
||||
get_node_id(inode) != o->nodeid ||
|
||||
((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
|
||||
d_invalidate(dentry);
|
||||
} else if (is_bad_inode(inode)) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
} else {
|
||||
struct fuse_inode *fi;
|
||||
fi = get_fuse_inode(inode);
|
||||
spin_lock(&fc->lock);
|
||||
fi->nlookup++;
|
||||
spin_unlock(&fc->lock);
|
||||
|
||||
fuse_change_attributes(inode, &o->attr,
|
||||
entry_attr_timeout(o),
|
||||
attr_version);
|
||||
|
||||
/*
|
||||
* The other branch to 'found' comes via fuse_iget()
|
||||
* which bumps nlookup inside
|
||||
*/
|
||||
goto found;
|
||||
dput(dentry);
|
||||
goto retry;
|
||||
}
|
||||
dput(dentry);
|
||||
if (is_bad_inode(inode)) {
|
||||
dput(dentry);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fi = get_fuse_inode(inode);
|
||||
spin_lock(&fc->lock);
|
||||
fi->nlookup++;
|
||||
spin_unlock(&fc->lock);
|
||||
|
||||
fuse_change_attributes(inode, &o->attr,
|
||||
entry_attr_timeout(o),
|
||||
attr_version);
|
||||
/*
|
||||
* The other branch comes via fuse_iget()
|
||||
* which bumps nlookup inside
|
||||
*/
|
||||
} else {
|
||||
inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
|
||||
&o->attr, entry_attr_timeout(o),
|
||||
attr_version);
|
||||
if (!inode)
|
||||
inode = ERR_PTR(-ENOMEM);
|
||||
|
||||
alias = d_splice_alias(inode, dentry);
|
||||
d_lookup_done(dentry);
|
||||
if (alias) {
|
||||
dput(dentry);
|
||||
dentry = alias;
|
||||
}
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
}
|
||||
|
||||
dentry = d_alloc(parent, &name);
|
||||
err = -ENOMEM;
|
||||
if (!dentry)
|
||||
goto out;
|
||||
|
||||
inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
|
||||
&o->attr, entry_attr_timeout(o), attr_version);
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
alias = d_splice_alias(inode, dentry);
|
||||
err = PTR_ERR(alias);
|
||||
if (IS_ERR(alias))
|
||||
goto out;
|
||||
|
||||
if (alias) {
|
||||
dput(dentry);
|
||||
dentry = alias;
|
||||
}
|
||||
|
||||
found:
|
||||
if (fc->readdirplus_auto)
|
||||
set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
|
||||
fuse_change_entry_timeout(dentry, o);
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
dput(dentry);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
|
||||
@ -1759,10 +1755,9 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
|
||||
void *value, size_t size)
|
||||
static ssize_t fuse_getxattr(struct dentry *entry, struct inode *inode,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(entry);
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
FUSE_ARGS(args);
|
||||
struct fuse_getxattr_in inarg;
|
||||
@ -1893,7 +1888,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
|
||||
static const struct file_operations fuse_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = fuse_readdir,
|
||||
.iterate_shared = fuse_readdir,
|
||||
.open = fuse_dir_open,
|
||||
.release = fuse_dir_release,
|
||||
.fsync = fuse_dir_fsync,
|
||||
|
@ -1119,7 +1119,7 @@ const struct file_operations gfs2_file_fops = {
|
||||
};
|
||||
|
||||
const struct file_operations gfs2_dir_fops = {
|
||||
.iterate = gfs2_readdir,
|
||||
.iterate_shared = gfs2_readdir,
|
||||
.unlocked_ioctl = gfs2_ioctl,
|
||||
.open = gfs2_open,
|
||||
.release = gfs2_release,
|
||||
@ -1147,7 +1147,7 @@ const struct file_operations gfs2_file_fops_nolock = {
|
||||
};
|
||||
|
||||
const struct file_operations gfs2_dir_fops_nolock = {
|
||||
.iterate = gfs2_readdir,
|
||||
.iterate_shared = gfs2_readdir,
|
||||
.unlocked_ioctl = gfs2_ioctl,
|
||||
.open = gfs2_open,
|
||||
.release = gfs2_release,
|
||||
|
@ -1968,22 +1968,21 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
|
||||
void *data, size_t size)
|
||||
static ssize_t gfs2_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *data, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
int ret;
|
||||
|
||||
/* For selinux during lookup */
|
||||
if (gfs2_glock_is_locked_by_me(ip->i_gl))
|
||||
return generic_getxattr(dentry, name, data, size);
|
||||
return generic_getxattr(dentry, inode, name, data, size);
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
if (ret == 0) {
|
||||
ret = generic_getxattr(dentry, name, data, size);
|
||||
ret = generic_getxattr(dentry, inode, name, data, size);
|
||||
gfs2_glock_dq(&gh);
|
||||
}
|
||||
gfs2_holder_uninit(&gh);
|
||||
|
@ -824,7 +824,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
|
||||
* i_mutex on quota files is special. Since this inode is hidden system
|
||||
* file, we are safe to define locking ourselves.
|
||||
*/
|
||||
lockdep_set_class(&sdp->sd_quota_inode->i_mutex,
|
||||
lockdep_set_class(&sdp->sd_quota_inode->i_rwsem,
|
||||
&gfs2_quota_imutex_key);
|
||||
|
||||
error = gfs2_rindex_update(sdp);
|
||||
@ -1360,7 +1360,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type,
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags,
|
||||
d_inode(path.dentry)->i_sb->s_bdev);
|
||||
path.dentry->d_sb->s_bdev);
|
||||
path_put(&path);
|
||||
if (IS_ERR(s)) {
|
||||
pr_warn("gfs2 mount does not exist\n");
|
||||
|
@ -1176,7 +1176,7 @@ static int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *s
|
||||
|
||||
static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
struct super_block *sb = d_inode(dentry)->i_sb;
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||
struct gfs2_statfs_change_host sc;
|
||||
int error;
|
||||
|
@ -584,10 +584,10 @@ out:
|
||||
* Returns: actual size of data on success, -errno on error
|
||||
*/
|
||||
static int gfs2_xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_ea_location el;
|
||||
int type = handler->flags;
|
||||
int error;
|
||||
|
@ -56,10 +56,9 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size)
|
||||
ssize_t hfs_getxattr(struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct hfs_find_data fd;
|
||||
hfs_cat_rec rec;
|
||||
struct hfs_cat_file *file;
|
||||
|
@ -240,10 +240,13 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
|
||||
}
|
||||
}
|
||||
|
||||
/* we only need to take spinlock for exclusion with ->release() */
|
||||
spin_lock(&HFS_I(dir)->open_dir_lock);
|
||||
list_for_each_entry(rd, &HFS_I(dir)->open_dir_list, list) {
|
||||
if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
|
||||
rd->file->f_pos--;
|
||||
}
|
||||
spin_unlock(&HFS_I(dir)->open_dir_lock);
|
||||
|
||||
res = hfs_brec_remove(&fd);
|
||||
if (res)
|
||||
|
12
fs/hfs/dir.c
12
fs/hfs/dir.c
@ -161,8 +161,14 @@ static int hfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
}
|
||||
file->private_data = rd;
|
||||
rd->file = file;
|
||||
spin_lock(&HFS_I(inode)->open_dir_lock);
|
||||
list_add(&rd->list, &HFS_I(inode)->open_dir_list);
|
||||
spin_unlock(&HFS_I(inode)->open_dir_lock);
|
||||
}
|
||||
/*
|
||||
* Can be done after the list insertion; exclusion with
|
||||
* hfs_delete_cat() is provided by directory lock.
|
||||
*/
|
||||
memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
|
||||
out:
|
||||
hfs_find_exit(&fd);
|
||||
@ -173,9 +179,9 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct hfs_readdir_data *rd = file->private_data;
|
||||
if (rd) {
|
||||
inode_lock(inode);
|
||||
spin_lock(&HFS_I(inode)->open_dir_lock);
|
||||
list_del(&rd->list);
|
||||
inode_unlock(inode);
|
||||
spin_unlock(&HFS_I(inode)->open_dir_lock);
|
||||
kfree(rd);
|
||||
}
|
||||
return 0;
|
||||
@ -303,7 +309,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
const struct file_operations hfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.iterate = hfs_readdir,
|
||||
.iterate_shared = hfs_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
.release = hfs_dir_release,
|
||||
};
|
||||
|
@ -69,6 +69,7 @@ struct hfs_inode_info {
|
||||
struct hfs_cat_key cat_key;
|
||||
|
||||
struct list_head open_dir_list;
|
||||
spinlock_t open_dir_lock;
|
||||
struct inode *rsrc_inode;
|
||||
|
||||
struct mutex extents_lock;
|
||||
@ -213,8 +214,8 @@ extern void hfs_delete_inode(struct inode *);
|
||||
/* attr.c */
|
||||
extern int hfs_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
extern ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size);
|
||||
extern ssize_t hfs_getxattr(struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *value, size_t size);
|
||||
extern ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
|
||||
/* mdb.c */
|
||||
|
@ -187,6 +187,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
|
||||
|
||||
mutex_init(&HFS_I(inode)->extents_lock);
|
||||
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFS_I(inode)->open_dir_lock);
|
||||
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
|
||||
inode->i_ino = HFS_SB(sb)->next_id++;
|
||||
inode->i_mode = mode;
|
||||
@ -318,6 +319,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
|
||||
HFS_I(inode)->rsrc_inode = NULL;
|
||||
mutex_init(&HFS_I(inode)->extents_lock);
|
||||
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFS_I(inode)->open_dir_lock);
|
||||
|
||||
/* Initialize the inode */
|
||||
inode->i_uid = hsb->s_uid;
|
||||
|
@ -374,12 +374,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
|
||||
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
|
||||
}
|
||||
|
||||
/* we only need to take spinlock for exclusion with ->release() */
|
||||
spin_lock(&HFSPLUS_I(dir)->open_dir_lock);
|
||||
list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) {
|
||||
struct hfsplus_readdir_data *rd =
|
||||
list_entry(pos, struct hfsplus_readdir_data, list);
|
||||
if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
|
||||
rd->file->f_pos--;
|
||||
}
|
||||
spin_unlock(&HFSPLUS_I(dir)->open_dir_lock);
|
||||
|
||||
err = hfs_brec_remove(&fd);
|
||||
if (err)
|
||||
|
@ -271,8 +271,14 @@ next:
|
||||
}
|
||||
file->private_data = rd;
|
||||
rd->file = file;
|
||||
spin_lock(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
|
||||
spin_unlock(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
}
|
||||
/*
|
||||
* Can be done after the list insertion; exclusion with
|
||||
* hfsplus_delete_cat() is provided by directory lock.
|
||||
*/
|
||||
memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
|
||||
out:
|
||||
kfree(strbuf);
|
||||
@ -284,9 +290,9 @@ static int hfsplus_dir_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct hfsplus_readdir_data *rd = file->private_data;
|
||||
if (rd) {
|
||||
inode_lock(inode);
|
||||
spin_lock(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
list_del(&rd->list);
|
||||
inode_unlock(inode);
|
||||
spin_unlock(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
kfree(rd);
|
||||
}
|
||||
return 0;
|
||||
@ -569,7 +575,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
|
||||
const struct file_operations hfsplus_dir_operations = {
|
||||
.fsync = hfsplus_file_fsync,
|
||||
.read = generic_read_dir,
|
||||
.iterate = hfsplus_readdir,
|
||||
.iterate_shared = hfsplus_readdir,
|
||||
.unlocked_ioctl = hfsplus_ioctl,
|
||||
.llseek = generic_file_llseek,
|
||||
.release = hfsplus_dir_release,
|
||||
|
@ -244,6 +244,7 @@ struct hfsplus_inode_info {
|
||||
u8 userflags; /* BSD user file flags */
|
||||
u32 subfolders; /* Subfolder count (HFSX only) */
|
||||
struct list_head open_dir_list;
|
||||
spinlock_t open_dir_lock;
|
||||
loff_t phys_size;
|
||||
|
||||
struct inode vfs_inode;
|
||||
|
@ -374,6 +374,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
|
||||
|
||||
hip = HFSPLUS_I(inode);
|
||||
INIT_LIST_HEAD(&hip->open_dir_list);
|
||||
spin_lock_init(&hip->open_dir_lock);
|
||||
mutex_init(&hip->extents_lock);
|
||||
atomic_set(&hip->opencnt, 0);
|
||||
hip->extent_state = 0;
|
||||
|
@ -48,9 +48,6 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
|
||||
|
||||
hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
|
||||
return inode;
|
||||
|
||||
INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
mutex_init(&HFSPLUS_I(inode)->extents_lock);
|
||||
HFSPLUS_I(inode)->flags = 0;
|
||||
HFSPLUS_I(inode)->extent_state = 0;
|
||||
|
@ -579,7 +579,7 @@ failed_getxattr_init:
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
|
||||
ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
|
||||
void *value, size_t size,
|
||||
const char *prefix, size_t prefixlen)
|
||||
{
|
||||
@ -594,7 +594,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
|
||||
strcpy(xattr_name, prefix);
|
||||
strcpy(xattr_name + prefixlen, name);
|
||||
|
||||
res = __hfsplus_getxattr(d_inode(dentry), xattr_name, value, size);
|
||||
res = __hfsplus_getxattr(inode, xattr_name, value, size);
|
||||
kfree(xattr_name);
|
||||
return res;
|
||||
|
||||
@ -844,8 +844,8 @@ end_removexattr:
|
||||
}
|
||||
|
||||
static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
/*
|
||||
* Don't allow retrieving properly prefixed attributes
|
||||
@ -860,7 +860,7 @@ static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
|
||||
* creates), so we pass the name through unmodified (after
|
||||
* ensuring it doesn't conflict with another namespace).
|
||||
*/
|
||||
return __hfsplus_getxattr(d_inode(dentry), name, buffer, size);
|
||||
return __hfsplus_getxattr(inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
|
||||
|
@ -28,7 +28,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
|
||||
ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
|
||||
void *value, size_t size);
|
||||
|
||||
ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
|
||||
ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
|
||||
void *value, size_t size,
|
||||
const char *prefix, size_t prefixlen);
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
#include "acl.h"
|
||||
|
||||
static int hfsplus_security_getxattr(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return hfsplus_getxattr(dentry, name, buffer, size,
|
||||
return hfsplus_getxattr(inode, name, buffer, size,
|
||||
XATTR_SECURITY_PREFIX,
|
||||
XATTR_SECURITY_PREFIX_LEN);
|
||||
}
|
||||
|
@ -12,10 +12,10 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static int hfsplus_trusted_getxattr(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return hfsplus_getxattr(dentry, name, buffer, size,
|
||||
return hfsplus_getxattr(inode, name, buffer, size,
|
||||
XATTR_TRUSTED_PREFIX,
|
||||
XATTR_TRUSTED_PREFIX_LEN);
|
||||
}
|
||||
|
@ -12,11 +12,11 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static int hfsplus_user_getxattr(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size)
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
|
||||
return hfsplus_getxattr(dentry, name, buffer, size,
|
||||
return hfsplus_getxattr(inode, name, buffer, size,
|
||||
XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,7 @@ static const struct file_operations hostfs_file_fops = {
|
||||
|
||||
static const struct file_operations hostfs_dir_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.iterate = hostfs_readdir,
|
||||
.iterate_shared = hostfs_readdir,
|
||||
.read = generic_read_dir,
|
||||
.open = hostfs_open,
|
||||
.fsync = hostfs_fsync,
|
||||
|
@ -44,7 +44,11 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
|
||||
else goto fail;
|
||||
if (pos == 12) goto fail;
|
||||
}
|
||||
hpfs_add_pos(i, &filp->f_pos);
|
||||
if (unlikely(hpfs_add_pos(i, &filp->f_pos) < 0)) {
|
||||
hpfs_unlock(s);
|
||||
inode_unlock(i);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ok:
|
||||
filp->f_pos = new_off;
|
||||
hpfs_unlock(s);
|
||||
@ -141,8 +145,10 @@ static int hpfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
ctx->pos = 1;
|
||||
}
|
||||
if (ctx->pos == 1) {
|
||||
ret = hpfs_add_pos(inode, &file->f_pos);
|
||||
if (unlikely(ret < 0))
|
||||
goto out;
|
||||
ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
|
||||
hpfs_add_pos(inode, &file->f_pos);
|
||||
file->f_version = inode->i_version;
|
||||
}
|
||||
next_pos = ctx->pos;
|
||||
@ -324,7 +330,7 @@ const struct file_operations hpfs_dir_ops =
|
||||
{
|
||||
.llseek = hpfs_dir_lseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = hpfs_readdir,
|
||||
.iterate_shared = hpfs_readdir,
|
||||
.release = hpfs_dir_release,
|
||||
.fsync = hpfs_file_fsync,
|
||||
.unlocked_ioctl = hpfs_ioctl,
|
||||
|
@ -21,7 +21,7 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
|
||||
return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1;
|
||||
}
|
||||
|
||||
void hpfs_add_pos(struct inode *inode, loff_t *pos)
|
||||
int hpfs_add_pos(struct inode *inode, loff_t *pos)
|
||||
{
|
||||
struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
|
||||
int i = 0;
|
||||
@ -29,11 +29,12 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos)
|
||||
|
||||
if (hpfs_inode->i_rddir_off)
|
||||
for (; hpfs_inode->i_rddir_off[i]; i++)
|
||||
if (hpfs_inode->i_rddir_off[i] == pos) return;
|
||||
if (hpfs_inode->i_rddir_off[i] == pos)
|
||||
return 0;
|
||||
if (!(i&0x0f)) {
|
||||
if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) {
|
||||
pr_err("out of memory for position list\n");
|
||||
return;
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (hpfs_inode->i_rddir_off) {
|
||||
memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
|
||||
@ -43,6 +44,7 @@ void hpfs_add_pos(struct inode *inode, loff_t *pos)
|
||||
}
|
||||
hpfs_inode->i_rddir_off[i] = pos;
|
||||
hpfs_inode->i_rddir_off[i + 1] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hpfs_del_pos(struct inode *inode, loff_t *pos)
|
||||
|
@ -242,7 +242,7 @@ extern const struct file_operations hpfs_dir_ops;
|
||||
|
||||
/* dnode.c */
|
||||
|
||||
void hpfs_add_pos(struct inode *, loff_t *);
|
||||
int hpfs_add_pos(struct inode *, loff_t *);
|
||||
void hpfs_del_pos(struct inode *, loff_t *);
|
||||
struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *,
|
||||
const unsigned char *, unsigned, secno);
|
||||
|
17
fs/inode.c
17
fs/inode.c
@ -151,6 +151,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
|
||||
inode->i_bdev = NULL;
|
||||
inode->i_cdev = NULL;
|
||||
inode->i_link = NULL;
|
||||
inode->i_dir_seq = 0;
|
||||
inode->i_rdev = 0;
|
||||
inode->dirtied_when = 0;
|
||||
|
||||
@ -165,8 +166,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
|
||||
spin_lock_init(&inode->i_lock);
|
||||
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
|
||||
|
||||
mutex_init(&inode->i_mutex);
|
||||
lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
|
||||
init_rwsem(&inode->i_rwsem);
|
||||
lockdep_set_class(&inode->i_rwsem, &sb->s_type->i_mutex_key);
|
||||
|
||||
atomic_set(&inode->i_dio_count, 0);
|
||||
|
||||
@ -238,9 +239,9 @@ void __destroy_inode(struct inode *inode)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
|
||||
if (inode->i_acl && !is_uncached_acl(inode->i_acl))
|
||||
posix_acl_release(inode->i_acl);
|
||||
if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED)
|
||||
if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl))
|
||||
posix_acl_release(inode->i_default_acl);
|
||||
#endif
|
||||
this_cpu_dec(nr_inodes);
|
||||
@ -924,13 +925,13 @@ void lockdep_annotate_inode_mutex_key(struct inode *inode)
|
||||
struct file_system_type *type = inode->i_sb->s_type;
|
||||
|
||||
/* Set new key only if filesystem hasn't already changed it */
|
||||
if (lockdep_match_class(&inode->i_mutex, &type->i_mutex_key)) {
|
||||
if (lockdep_match_class(&inode->i_rwsem, &type->i_mutex_key)) {
|
||||
/*
|
||||
* ensure nobody is actually holding i_mutex
|
||||
*/
|
||||
mutex_destroy(&inode->i_mutex);
|
||||
mutex_init(&inode->i_mutex);
|
||||
lockdep_set_class(&inode->i_mutex,
|
||||
// mutex_destroy(&inode->i_mutex);
|
||||
init_rwsem(&inode->i_rwsem);
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&type->i_mutex_dir_key);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ int get_acorn_filename(struct iso_directory_record *de,
|
||||
std = sizeof(struct iso_directory_record) + de->name_len[0];
|
||||
if (std & 1)
|
||||
std++;
|
||||
if ((*((unsigned char *) de) - std) != 32)
|
||||
if (de->length[0] - std != 32)
|
||||
return retnamlen;
|
||||
chr = ((unsigned char *) de) + std;
|
||||
if (strncmp(chr, "ARCHIMEDES", 10))
|
||||
@ -269,7 +269,7 @@ const struct file_operations isofs_dir_operations =
|
||||
{
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = isofs_readdir,
|
||||
.iterate_shared = isofs_readdir,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -203,8 +203,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
|
||||
acl = ERR_PTR(rc);
|
||||
}
|
||||
kfree(value);
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ static int jffs2_rename (struct inode *, struct dentry *,
|
||||
const struct file_operations jffs2_dir_operations =
|
||||
{
|
||||
.read = generic_read_dir,
|
||||
.iterate = jffs2_readdir,
|
||||
.iterate_shared=jffs2_readdir,
|
||||
.unlocked_ioctl=jffs2_ioctl,
|
||||
.fsync = jffs2_fsync,
|
||||
.llseek = generic_file_llseek,
|
||||
@ -241,7 +241,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
|
||||
|
||||
static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
|
||||
{
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(d_inode(old_dentry)->i_sb);
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb);
|
||||
struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
|
||||
struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
|
||||
int ret;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user