Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more vfs updates from Al Viro: "Assorted cleanups and fixes. In the "trivial API change" department - ->d_compare() losing 'parent' argument" * 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: cachefiles: Fix race between inactivating and culling a cache object 9p: use clone_fid() 9p: fix braino introduced in "9p: new helper - v9fs_parent_fid()" vfs: make dentry_needs_remove_privs() internal vfs: remove file_needs_remove_privs() vfs: fix deadlock in file_remove_privs() on overlayfs get rid of 'parent' argument of ->d_compare() cifs, msdos, vfat, hfs+: don't bother with parent in ->d_compare() affs ->d_compare(): don't bother with ->d_inode fold _d_rehash() and __d_rehash() together fold dentry_rcuwalk_invalidate() into its only remaining caller
This commit is contained in:
commit
fe64f3283f
|
@ -12,7 +12,7 @@ prototypes:
|
||||||
int (*d_revalidate)(struct dentry *, unsigned int);
|
int (*d_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_hash)(const struct dentry *, struct qstr *);
|
int (*d_hash)(const struct dentry *, struct qstr *);
|
||||||
int (*d_compare)(const struct dentry *, const struct dentry *,
|
int (*d_compare)(const struct dentry *,
|
||||||
unsigned int, const char *, const struct qstr *);
|
unsigned int, const char *, const struct qstr *);
|
||||||
int (*d_delete)(struct dentry *);
|
int (*d_delete)(struct dentry *);
|
||||||
int (*d_init)(struct dentry *);
|
int (*d_init)(struct dentry *);
|
||||||
|
|
|
@ -585,3 +585,10 @@ in your dentry operations instead.
|
||||||
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
|
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
|
||||||
called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
|
called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
|
||||||
->d_instantiate() uses not just ->getxattr() but ->setxattr() as well.
|
->d_instantiate() uses not just ->getxattr() but ->setxattr() as well.
|
||||||
|
--
|
||||||
|
[mandatory]
|
||||||
|
->d_compare() doesn't get parent as a separate argument anymore. If you
|
||||||
|
used it for finding the struct super_block involved, dentry->d_sb will
|
||||||
|
work just as well; if it's something more complicated, use dentry->d_parent.
|
||||||
|
Just be careful not to assume that fetching it more than once will yield
|
||||||
|
the same value - in RCU mode it could change under you.
|
||||||
|
|
|
@ -931,7 +931,7 @@ struct dentry_operations {
|
||||||
int (*d_revalidate)(struct dentry *, unsigned int);
|
int (*d_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_hash)(const struct dentry *, struct qstr *);
|
int (*d_hash)(const struct dentry *, struct qstr *);
|
||||||
int (*d_compare)(const struct dentry *, const struct dentry *,
|
int (*d_compare)(const struct dentry *,
|
||||||
unsigned int, const char *, const struct qstr *);
|
unsigned int, const char *, const struct qstr *);
|
||||||
int (*d_delete)(const struct dentry *);
|
int (*d_delete)(const struct dentry *);
|
||||||
int (*d_init)(struct dentry *);
|
int (*d_init)(struct dentry *);
|
||||||
|
|
|
@ -78,7 +78,7 @@ static void ll_release(struct dentry *de)
|
||||||
* INVALID) so d_lookup() matches it, but we have no lock on it (so
|
* INVALID) so d_lookup() matches it, but we have no lock on it (so
|
||||||
* lock_match() fails) and we spin around real_lookup().
|
* lock_match() fails) and we spin around real_lookup().
|
||||||
*/
|
*/
|
||||||
static int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
|
static int ll_dcompare(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str,
|
unsigned int len, const char *str,
|
||||||
const struct qstr *name)
|
const struct qstr *name)
|
||||||
{
|
{
|
||||||
|
|
26
fs/9p/fid.c
26
fs/9p/fid.c
|
@ -257,36 +257,12 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
|
||||||
return v9fs_fid_lookup_with_uid(dentry, uid, any);
|
return v9fs_fid_lookup_with_uid(dentry, uid, any);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
|
|
||||||
{
|
|
||||||
struct p9_fid *fid, *ret;
|
|
||||||
|
|
||||||
fid = v9fs_fid_lookup(dentry);
|
|
||||||
if (IS_ERR(fid))
|
|
||||||
return fid;
|
|
||||||
|
|
||||||
ret = p9_client_walk(fid, 0, NULL, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, kuid_t uid)
|
|
||||||
{
|
|
||||||
struct p9_fid *fid, *ret;
|
|
||||||
|
|
||||||
fid = v9fs_fid_lookup_with_uid(dentry, uid, 0);
|
|
||||||
if (IS_ERR(fid))
|
|
||||||
return fid;
|
|
||||||
|
|
||||||
ret = p9_client_walk(fid, 0, NULL, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
|
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
|
|
||||||
fid = v9fs_fid_clone_with_uid(dentry, GLOBAL_ROOT_UID);
|
fid = clone_fid(v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0));
|
||||||
if (IS_ERR(fid))
|
if (IS_ERR(fid))
|
||||||
goto error_out;
|
goto error_out;
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -28,7 +28,14 @@ static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
return v9fs_fid_lookup(dentry->d_parent);
|
return v9fs_fid_lookup(dentry->d_parent);
|
||||||
}
|
}
|
||||||
struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
|
|
||||||
void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
|
void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
|
||||||
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
|
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
|
||||||
|
static inline struct p9_fid *clone_fid(struct p9_fid *fid)
|
||||||
|
{
|
||||||
|
return IS_ERR(fid) ? fid : p9_client_walk(fid, 0, NULL, 1);
|
||||||
|
}
|
||||||
|
static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return clone_fid(v9fs_fid_lookup(dentry));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -661,7 +661,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clone a fid to use for creation */
|
/* clone a fid to use for creation */
|
||||||
ofid = p9_client_walk(dfid, 0, NULL, 1);
|
ofid = clone_fid(dfid);
|
||||||
if (IS_ERR(ofid)) {
|
if (IS_ERR(ofid)) {
|
||||||
err = PTR_ERR(ofid);
|
err = PTR_ERR(ofid);
|
||||||
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
||||||
|
@ -975,13 +975,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
if (IS_ERR(oldfid))
|
if (IS_ERR(oldfid))
|
||||||
return PTR_ERR(oldfid);
|
return PTR_ERR(oldfid);
|
||||||
|
|
||||||
olddirfid = v9fs_parent_fid(old_dentry);
|
olddirfid = clone_fid(v9fs_parent_fid(old_dentry));
|
||||||
if (IS_ERR(olddirfid)) {
|
if (IS_ERR(olddirfid)) {
|
||||||
retval = PTR_ERR(olddirfid);
|
retval = PTR_ERR(olddirfid);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
newdirfid = v9fs_parent_fid(new_dentry);
|
newdirfid = clone_fid(v9fs_parent_fid(new_dentry));
|
||||||
if (IS_ERR(newdirfid)) {
|
if (IS_ERR(newdirfid)) {
|
||||||
retval = PTR_ERR(newdirfid);
|
retval = PTR_ERR(newdirfid);
|
||||||
goto clunk_olddir;
|
goto clunk_olddir;
|
||||||
|
|
|
@ -281,7 +281,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clone a fid to use for creation */
|
/* clone a fid to use for creation */
|
||||||
ofid = p9_client_walk(dfid, 0, NULL, 1);
|
ofid = clone_fid(dfid);
|
||||||
if (IS_ERR(ofid)) {
|
if (IS_ERR(ofid)) {
|
||||||
err = PTR_ERR(ofid);
|
err = PTR_ERR(ofid);
|
||||||
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
||||||
|
|
|
@ -97,8 +97,6 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
|
||||||
const void *value, size_t value_len, int flags)
|
const void *value, size_t value_len, int flags)
|
||||||
{
|
{
|
||||||
struct p9_fid *fid = v9fs_fid_lookup(dentry);
|
struct p9_fid *fid = v9fs_fid_lookup(dentry);
|
||||||
if (IS_ERR(fid))
|
|
||||||
return PTR_ERR(fid);
|
|
||||||
return v9fs_fid_xattr_set(fid, name, value, value_len, flags);
|
return v9fs_fid_xattr_set(fid, name, value, value_len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +113,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
|
||||||
name, value_len, flags);
|
name, value_len, flags);
|
||||||
|
|
||||||
/* Clone it */
|
/* Clone it */
|
||||||
fid = p9_client_walk(fid, 0, NULL, 1);
|
fid = clone_fid(fid);
|
||||||
if (IS_ERR(fid))
|
if (IS_ERR(fid))
|
||||||
return PTR_ERR(fid);
|
return PTR_ERR(fid);
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
|
||||||
* requirements of the underlying filesystem.
|
* requirements of the underlying filesystem.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
adfs_compare(const struct dentry *parent, const struct dentry *dentry,
|
adfs_compare(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -472,9 +472,7 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
|
||||||
bool
|
bool
|
||||||
affs_nofilenametruncate(const struct dentry *dentry)
|
affs_nofilenametruncate(const struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = d_inode(dentry);
|
return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE);
|
||||||
|
|
||||||
return affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_NO_TRUNCATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the name is valid for a affs object. */
|
/* Check if the name is valid for a affs object. */
|
||||||
|
|
|
@ -14,11 +14,11 @@ typedef int (*toupper_t)(int);
|
||||||
|
|
||||||
static int affs_toupper(int ch);
|
static int affs_toupper(int ch);
|
||||||
static int affs_hash_dentry(const struct dentry *, struct qstr *);
|
static int affs_hash_dentry(const struct dentry *, struct qstr *);
|
||||||
static int affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
static int affs_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
static int affs_intl_toupper(int ch);
|
static int affs_intl_toupper(int ch);
|
||||||
static int affs_intl_hash_dentry(const struct dentry *, struct qstr *);
|
static int affs_intl_hash_dentry(const struct dentry *, struct qstr *);
|
||||||
static int affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
static int affs_intl_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
|
|
||||||
const struct dentry_operations affs_dentry_operations = {
|
const struct dentry_operations affs_dentry_operations = {
|
||||||
|
@ -131,20 +131,20 @@ static inline int __affs_compare_dentry(unsigned int len,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
affs_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
|
|
||||||
return __affs_compare_dentry(len, str, name, affs_toupper,
|
return __affs_compare_dentry(len, str, name, affs_toupper,
|
||||||
affs_nofilenametruncate(parent));
|
affs_nofilenametruncate(dentry));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
affs_intl_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
return __affs_compare_dentry(len, str, name, affs_intl_toupper,
|
return __affs_compare_dentry(len, str, name, affs_intl_toupper,
|
||||||
affs_nofilenametruncate(parent));
|
affs_nofilenametruncate(dentry));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,8 @@ requeue:
|
||||||
void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
|
void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
|
||||||
struct cachefiles_object *object)
|
struct cachefiles_object *object)
|
||||||
{
|
{
|
||||||
|
blkcnt_t i_blocks = d_backing_inode(object->dentry)->i_blocks;
|
||||||
|
|
||||||
write_lock(&cache->active_lock);
|
write_lock(&cache->active_lock);
|
||||||
rb_erase(&object->active_node, &cache->active_nodes);
|
rb_erase(&object->active_node, &cache->active_nodes);
|
||||||
clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
|
clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
|
||||||
|
@ -273,8 +275,7 @@ void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
|
||||||
/* This object can now be culled, so we need to let the daemon know
|
/* This object can now be culled, so we need to let the daemon know
|
||||||
* that there is something it can remove if it needs to.
|
* that there is something it can remove if it needs to.
|
||||||
*/
|
*/
|
||||||
atomic_long_add(d_backing_inode(object->dentry)->i_blocks,
|
atomic_long_add(i_blocks, &cache->b_released);
|
||||||
&cache->b_released);
|
|
||||||
if (atomic_inc_return(&cache->f_released))
|
if (atomic_inc_return(&cache->f_released))
|
||||||
cachefiles_state_changed(cache);
|
cachefiles_state_changed(cache);
|
||||||
}
|
}
|
||||||
|
|
|
@ -903,10 +903,10 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
|
static int cifs_ci_compare(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
|
struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
|
||||||
wchar_t c1, c2;
|
wchar_t c1, c2;
|
||||||
int i, l1, l2;
|
int i, l1, l2;
|
||||||
|
|
||||||
|
|
55
fs/dcache.c
55
fs/dcache.c
|
@ -316,20 +316,6 @@ static void dentry_free(struct dentry *dentry)
|
||||||
call_rcu(&dentry->d_u.d_rcu, __d_free);
|
call_rcu(&dentry->d_u.d_rcu, __d_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* dentry_rcuwalk_invalidate - invalidate in-progress rcu-walk lookups
|
|
||||||
* @dentry: the target dentry
|
|
||||||
* After this call, in-progress rcu-walk path lookup will fail. This
|
|
||||||
* should be called after unhashing, and after changing d_inode (if
|
|
||||||
* the dentry has not already been unhashed).
|
|
||||||
*/
|
|
||||||
static inline void dentry_rcuwalk_invalidate(struct dentry *dentry)
|
|
||||||
{
|
|
||||||
lockdep_assert_held(&dentry->d_lock);
|
|
||||||
/* Go through am invalidation barrier */
|
|
||||||
write_seqcount_invalidate(&dentry->d_seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release the dentry's inode, using the filesystem
|
* Release the dentry's inode, using the filesystem
|
||||||
* d_iput() operation if defined.
|
* d_iput() operation if defined.
|
||||||
|
@ -468,7 +454,8 @@ void __d_drop(struct dentry *dentry)
|
||||||
__hlist_bl_del(&dentry->d_hash);
|
__hlist_bl_del(&dentry->d_hash);
|
||||||
dentry->d_hash.pprev = NULL;
|
dentry->d_hash.pprev = NULL;
|
||||||
hlist_bl_unlock(b);
|
hlist_bl_unlock(b);
|
||||||
dentry_rcuwalk_invalidate(dentry);
|
/* After this call, in-progress rcu-walk path lookup will fail. */
|
||||||
|
write_seqcount_invalidate(&dentry->d_seq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__d_drop);
|
EXPORT_SYMBOL(__d_drop);
|
||||||
|
@ -2060,7 +2047,7 @@ static inline bool d_same_name(const struct dentry *dentry,
|
||||||
return false;
|
return false;
|
||||||
return dentry_cmp(dentry, name->name, name->len) == 0;
|
return dentry_cmp(dentry, name->name, name->len) == 0;
|
||||||
}
|
}
|
||||||
return parent->d_op->d_compare(parent, dentry,
|
return parent->d_op->d_compare(dentry,
|
||||||
dentry->d_name.len, dentry->d_name.name,
|
dentry->d_name.len, dentry->d_name.name,
|
||||||
name) == 0;
|
name) == 0;
|
||||||
}
|
}
|
||||||
|
@ -2163,7 +2150,7 @@ seqretry:
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
goto seqretry;
|
goto seqretry;
|
||||||
}
|
}
|
||||||
if (parent->d_op->d_compare(parent, dentry,
|
if (parent->d_op->d_compare(dentry,
|
||||||
tlen, tname, name) != 0)
|
tlen, tname, name) != 0)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2352,19 +2339,15 @@ again:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_delete);
|
EXPORT_SYMBOL(d_delete);
|
||||||
|
|
||||||
static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
|
static void __d_rehash(struct dentry *entry)
|
||||||
{
|
{
|
||||||
|
struct hlist_bl_head *b = d_hash(entry->d_name.hash);
|
||||||
BUG_ON(!d_unhashed(entry));
|
BUG_ON(!d_unhashed(entry));
|
||||||
hlist_bl_lock(b);
|
hlist_bl_lock(b);
|
||||||
hlist_bl_add_head_rcu(&entry->d_hash, b);
|
hlist_bl_add_head_rcu(&entry->d_hash, b);
|
||||||
hlist_bl_unlock(b);
|
hlist_bl_unlock(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _d_rehash(struct dentry * entry)
|
|
||||||
{
|
|
||||||
__d_rehash(entry, d_hash(entry->d_name.hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* d_rehash - add an entry back to the hash
|
* d_rehash - add an entry back to the hash
|
||||||
* @entry: dentry to add to the hash
|
* @entry: dentry to add to the hash
|
||||||
|
@ -2375,7 +2358,7 @@ static void _d_rehash(struct dentry * entry)
|
||||||
void d_rehash(struct dentry * entry)
|
void d_rehash(struct dentry * entry)
|
||||||
{
|
{
|
||||||
spin_lock(&entry->d_lock);
|
spin_lock(&entry->d_lock);
|
||||||
_d_rehash(entry);
|
__d_rehash(entry);
|
||||||
spin_unlock(&entry->d_lock);
|
spin_unlock(&entry->d_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_rehash);
|
EXPORT_SYMBOL(d_rehash);
|
||||||
|
@ -2549,7 +2532,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
|
||||||
raw_write_seqcount_end(&dentry->d_seq);
|
raw_write_seqcount_end(&dentry->d_seq);
|
||||||
fsnotify_update_flags(dentry);
|
fsnotify_update_flags(dentry);
|
||||||
}
|
}
|
||||||
_d_rehash(dentry);
|
__d_rehash(dentry);
|
||||||
if (dir)
|
if (dir)
|
||||||
end_dir_add(dir, n);
|
end_dir_add(dir, n);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
@ -2611,7 +2594,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
|
||||||
alias = NULL;
|
alias = NULL;
|
||||||
} else {
|
} else {
|
||||||
__dget_dlock(alias);
|
__dget_dlock(alias);
|
||||||
_d_rehash(alias);
|
__d_rehash(alias);
|
||||||
spin_unlock(&alias->d_lock);
|
spin_unlock(&alias->d_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
|
@ -2795,23 +2778,10 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
||||||
write_seqcount_begin(&dentry->d_seq);
|
write_seqcount_begin(&dentry->d_seq);
|
||||||
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
|
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
|
||||||
|
|
||||||
|
/* unhash both */
|
||||||
/* __d_drop does write_seqcount_barrier, but they're OK to nest. */
|
/* __d_drop does write_seqcount_barrier, but they're OK to nest. */
|
||||||
|
|
||||||
/*
|
|
||||||
* Move the dentry to the target hash queue. Don't bother checking
|
|
||||||
* for the same hash queue because of how unlikely it is.
|
|
||||||
*/
|
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
__d_rehash(dentry, d_hash(target->d_name.hash));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unhash the target (d_delete() is not usable here). If exchanging
|
|
||||||
* the two dentries, then rehash onto the other's hash queue.
|
|
||||||
*/
|
|
||||||
__d_drop(target);
|
__d_drop(target);
|
||||||
if (exchange) {
|
|
||||||
__d_rehash(target, d_hash(dentry->d_name.hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Switch the names.. */
|
/* Switch the names.. */
|
||||||
if (exchange)
|
if (exchange)
|
||||||
|
@ -2819,6 +2789,11 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
||||||
else
|
else
|
||||||
copy_name(dentry, target);
|
copy_name(dentry, target);
|
||||||
|
|
||||||
|
/* rehash in new place(s) */
|
||||||
|
__d_rehash(dentry);
|
||||||
|
if (exchange)
|
||||||
|
__d_rehash(target);
|
||||||
|
|
||||||
/* ... and switch them in the tree */
|
/* ... and switch them in the tree */
|
||||||
if (IS_ROOT(dentry)) {
|
if (IS_ROOT(dentry)) {
|
||||||
/* splicing a tree */
|
/* splicing a tree */
|
||||||
|
|
|
@ -45,8 +45,7 @@ static struct super_block *efivarfs_sb;
|
||||||
* So we need to perform a case-sensitive match on part 1 and a
|
* So we need to perform a case-sensitive match on part 1 and a
|
||||||
* case-insensitive match on part 2.
|
* case-insensitive match on part 2.
|
||||||
*/
|
*/
|
||||||
static int efivarfs_d_compare(const struct dentry *parent,
|
static int efivarfs_d_compare(const struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
unsigned int len, const char *str,
|
unsigned int len, const char *str,
|
||||||
const struct qstr *name)
|
const struct qstr *name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,10 +162,10 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
|
||||||
* Compare two msdos names. If either of the names are invalid,
|
* Compare two msdos names. If either of the names are invalid,
|
||||||
* we fall back to doing the standard name comparison.
|
* we fall back to doing the standard name comparison.
|
||||||
*/
|
*/
|
||||||
static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
|
static int msdos_cmp(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
|
struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
|
||||||
unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
|
unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
|
@ -138,10 +138,10 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
|
||||||
/*
|
/*
|
||||||
* Case insensitive compare of two vfat names.
|
* Case insensitive compare of two vfat names.
|
||||||
*/
|
*/
|
||||||
static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
|
static int vfat_cmpi(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
|
struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
|
||||||
unsigned int alen, blen;
|
unsigned int alen, blen;
|
||||||
|
|
||||||
/* A filename cannot end in '.' or we treat it like it has none */
|
/* A filename cannot end in '.' or we treat it like it has none */
|
||||||
|
@ -157,7 +157,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
|
||||||
/*
|
/*
|
||||||
* Case sensitive compare of two vfat names.
|
* Case sensitive compare of two vfat names.
|
||||||
*/
|
*/
|
||||||
static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
|
static int vfat_cmp(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
unsigned int alen, blen;
|
unsigned int alen, blen;
|
||||||
|
|
|
@ -233,7 +233,7 @@ extern const struct dentry_operations hfs_dentry_operations;
|
||||||
extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
|
extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
|
||||||
extern int hfs_strcmp(const unsigned char *, unsigned int,
|
extern int hfs_strcmp(const unsigned char *, unsigned int,
|
||||||
const unsigned char *, unsigned int);
|
const unsigned char *, unsigned int);
|
||||||
extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
extern int hfs_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
|
|
||||||
/* trans.c */
|
/* trans.c */
|
||||||
|
|
|
@ -92,7 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
|
||||||
* Test for equality of two strings in the HFS filename character ordering.
|
* Test for equality of two strings in the HFS filename character ordering.
|
||||||
* return 1 on failure and 0 on success
|
* return 1 on failure and 0 on success
|
||||||
*/
|
*/
|
||||||
int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
int hfs_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
const unsigned char *n1, *n2;
|
const unsigned char *n1, *n2;
|
||||||
|
|
|
@ -520,8 +520,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr,
|
||||||
int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
|
int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
|
||||||
int max_unistr_len, const char *astr, int len);
|
int max_unistr_len, const char *astr, int len);
|
||||||
int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
|
int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
|
||||||
int hfsplus_compare_dentry(const struct dentry *parent,
|
int hfsplus_compare_dentry(const struct dentry *dentry, unsigned int len,
|
||||||
const struct dentry *dentry, unsigned int len,
|
|
||||||
const char *str, const struct qstr *name);
|
const char *str, const struct qstr *name);
|
||||||
|
|
||||||
/* wrapper.c */
|
/* wrapper.c */
|
||||||
|
|
|
@ -385,10 +385,10 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
|
||||||
* Composed unicode characters are decomposed and case-folding is performed
|
* Composed unicode characters are decomposed and case-folding is performed
|
||||||
* if the appropriate bits are (un)set on the superblock.
|
* if the appropriate bits are (un)set on the superblock.
|
||||||
*/
|
*/
|
||||||
int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
int hfsplus_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct super_block *sb = parent->d_sb;
|
struct super_block *sb = dentry->d_sb;
|
||||||
int casefold, decompose, size;
|
int casefold, decompose, size;
|
||||||
int dsize1, dsize2, len1, len2;
|
int dsize1, dsize2, len1, len2;
|
||||||
const u16 *dstr1, *dstr2;
|
const u16 *dstr1, *dstr2;
|
||||||
|
|
|
@ -34,7 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
static int hpfs_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
unsigned al = len;
|
unsigned al = len;
|
||||||
|
@ -50,7 +50,7 @@ static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry
|
||||||
|
|
||||||
if (hpfs_chk_name(name->name, &bl))
|
if (hpfs_chk_name(name->name, &bl))
|
||||||
return 1;
|
return 1;
|
||||||
if (hpfs_compare_names(parent->d_sb, str, al, name->name, bl, 0))
|
if (hpfs_compare_names(dentry->d_sb, str, al, name->name, bl, 0))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1729,7 +1729,6 @@ int dentry_needs_remove_privs(struct dentry *dentry)
|
||||||
mask |= ATTR_KILL_PRIV;
|
mask |= ATTR_KILL_PRIV;
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dentry_needs_remove_privs);
|
|
||||||
|
|
||||||
static int __remove_privs(struct dentry *dentry, int kill)
|
static int __remove_privs(struct dentry *dentry, int kill)
|
||||||
{
|
{
|
||||||
|
@ -1749,8 +1748,8 @@ static int __remove_privs(struct dentry *dentry, int kill)
|
||||||
*/
|
*/
|
||||||
int file_remove_privs(struct file *file)
|
int file_remove_privs(struct file *file)
|
||||||
{
|
{
|
||||||
struct dentry *dentry = file->f_path.dentry;
|
struct dentry *dentry = file_dentry(file);
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = file_inode(file);
|
||||||
int kill;
|
int kill;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
|
@ -1758,7 +1757,7 @@ int file_remove_privs(struct file *file)
|
||||||
if (IS_NOSEC(inode))
|
if (IS_NOSEC(inode))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
kill = file_needs_remove_privs(file);
|
kill = dentry_needs_remove_privs(dentry);
|
||||||
if (kill < 0)
|
if (kill < 0)
|
||||||
return kill;
|
return kill;
|
||||||
if (kill)
|
if (kill)
|
||||||
|
|
|
@ -117,6 +117,7 @@ extern int vfs_open(const struct path *, struct file *, const struct cred *);
|
||||||
*/
|
*/
|
||||||
extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
|
extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
|
||||||
extern void inode_add_lru(struct inode *inode);
|
extern void inode_add_lru(struct inode *inode);
|
||||||
|
extern int dentry_needs_remove_privs(struct dentry *dentry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fs-writeback.c
|
* fs-writeback.c
|
||||||
|
|
|
@ -29,18 +29,15 @@
|
||||||
#define BEQUIET
|
#define BEQUIET
|
||||||
|
|
||||||
static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
|
static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
|
||||||
static int isofs_dentry_cmpi(const struct dentry *parent,
|
static int isofs_dentry_cmpi(const struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
|
|
||||||
#ifdef CONFIG_JOLIET
|
#ifdef CONFIG_JOLIET
|
||||||
static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
|
static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
|
||||||
static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
|
static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
|
||||||
static int isofs_dentry_cmpi_ms(const struct dentry *parent,
|
static int isofs_dentry_cmpi_ms(const struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
static int isofs_dentry_cmp_ms(const struct dentry *parent,
|
static int isofs_dentry_cmp_ms(const struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
unsigned int len, const char *str, const struct qstr *name);
|
unsigned int len, const char *str, const struct qstr *name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -235,7 +232,7 @@ isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
|
isofs_dentry_cmpi(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
return isofs_dentry_cmp_common(len, str, name, 0, 1);
|
return isofs_dentry_cmp_common(len, str, name, 0, 1);
|
||||||
|
@ -276,14 +273,14 @@ isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
|
isofs_dentry_cmp_ms(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
return isofs_dentry_cmp_common(len, str, name, 1, 0);
|
return isofs_dentry_cmp_common(len, str, name, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
|
isofs_dentry_cmpi_ms(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
return isofs_dentry_cmp_common(len, str, name, 1, 1);
|
return isofs_dentry_cmp_common(len, str, name, 1, 1);
|
||||||
|
|
|
@ -22,7 +22,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
|
||||||
qstr.len = dlen;
|
qstr.len = dlen;
|
||||||
if (likely(!dentry->d_op))
|
if (likely(!dentry->d_op))
|
||||||
return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
|
return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
|
||||||
return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
|
return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1572,7 +1572,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
|
static int jfs_ci_compare(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
int i, result = 1;
|
int i, result = 1;
|
||||||
|
|
|
@ -74,7 +74,7 @@ const struct inode_operations ncp_dir_inode_operations =
|
||||||
*/
|
*/
|
||||||
static int ncp_lookup_validate(struct dentry *, unsigned int);
|
static int ncp_lookup_validate(struct dentry *, unsigned int);
|
||||||
static int ncp_hash_dentry(const struct dentry *, struct qstr *);
|
static int ncp_hash_dentry(const struct dentry *, struct qstr *);
|
||||||
static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
|
static int ncp_compare_dentry(const struct dentry *,
|
||||||
unsigned int, const char *, const struct qstr *);
|
unsigned int, const char *, const struct qstr *);
|
||||||
static int ncp_delete_dentry(const struct dentry *);
|
static int ncp_delete_dentry(const struct dentry *);
|
||||||
static void ncp_d_prune(struct dentry *dentry);
|
static void ncp_d_prune(struct dentry *dentry);
|
||||||
|
@ -154,7 +154,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
|
||||||
* the callers will handle races.
|
* the callers will handle races.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
ncp_compare_dentry(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct inode *pinode;
|
struct inode *pinode;
|
||||||
|
@ -162,7 +162,7 @@ ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
|
||||||
if (len != name->len)
|
if (len != name->len)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
pinode = d_inode_rcu(parent);
|
pinode = d_inode_rcu(dentry->d_parent);
|
||||||
if (!pinode)
|
if (!pinode)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
|
@ -834,7 +834,7 @@ static int sysctl_is_seen(struct ctl_table_header *p)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
|
static int proc_sys_compare(const struct dentry *dentry,
|
||||||
unsigned int len, const char *str, const struct qstr *name)
|
unsigned int len, const char *str, const struct qstr *name)
|
||||||
{
|
{
|
||||||
struct ctl_table_header *head;
|
struct ctl_table_header *head;
|
||||||
|
|
|
@ -130,7 +130,7 @@ struct dentry_operations {
|
||||||
int (*d_revalidate)(struct dentry *, unsigned int);
|
int (*d_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
int (*d_weak_revalidate)(struct dentry *, unsigned int);
|
||||||
int (*d_hash)(const struct dentry *, struct qstr *);
|
int (*d_hash)(const struct dentry *, struct qstr *);
|
||||||
int (*d_compare)(const struct dentry *, const struct dentry *,
|
int (*d_compare)(const struct dentry *,
|
||||||
unsigned int, const char *, const struct qstr *);
|
unsigned int, const char *, const struct qstr *);
|
||||||
int (*d_delete)(const struct dentry *);
|
int (*d_delete)(const struct dentry *);
|
||||||
int (*d_init)(struct dentry *);
|
int (*d_init)(struct dentry *);
|
||||||
|
|
|
@ -2748,11 +2748,6 @@ extern struct inode *new_inode(struct super_block *sb);
|
||||||
extern void free_inode_nonrcu(struct inode *inode);
|
extern void free_inode_nonrcu(struct inode *inode);
|
||||||
extern int should_remove_suid(struct dentry *);
|
extern int should_remove_suid(struct dentry *);
|
||||||
extern int file_remove_privs(struct file *);
|
extern int file_remove_privs(struct file *);
|
||||||
extern int dentry_needs_remove_privs(struct dentry *dentry);
|
|
||||||
static inline int file_needs_remove_privs(struct file *file)
|
|
||||||
{
|
|
||||||
return dentry_needs_remove_privs(file->f_path.dentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
|
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
|
||||||
static inline void insert_inode_hash(struct inode *inode)
|
static inline void insert_inode_hash(struct inode *inode)
|
||||||
|
|
Loading…
Reference in New Issue