fs: name case update method
smpfs and ncpfs want to update a live dentry name in-place. Rather than have them open code the locking, provide a documented dcache API. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
This commit is contained in:
parent
2bc334dcc7
commit
fb2d5b86af
4 changed files with 37 additions and 31 deletions
|
@ -145,8 +145,8 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
|
||||||
goto end_advance;
|
goto end_advance;
|
||||||
} else {
|
} else {
|
||||||
hashed = 1;
|
hashed = 1;
|
||||||
memcpy((char *) newdent->d_name.name, qname->name,
|
/* dir i_mutex is locked because we're in readdir */
|
||||||
newdent->d_name.len);
|
dentry_update_name_case(newdent, qname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newdent->d_inode) {
|
if (!newdent->d_inode) {
|
||||||
|
|
27
fs/dcache.c
27
fs/dcache.c
|
@ -1589,6 +1589,33 @@ void d_rehash(struct dentry * entry)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_rehash);
|
EXPORT_SYMBOL(d_rehash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dentry_update_name_case - update case insensitive dentry with a new name
|
||||||
|
* @dentry: dentry to be updated
|
||||||
|
* @name: new name
|
||||||
|
*
|
||||||
|
* Update a case insensitive dentry with new case of name.
|
||||||
|
*
|
||||||
|
* dentry must have been returned by d_lookup with name @name. Old and new
|
||||||
|
* name lengths must match (ie. no d_compare which allows mismatched name
|
||||||
|
* lengths).
|
||||||
|
*
|
||||||
|
* Parent inode i_mutex must be held over d_lookup and into this call (to
|
||||||
|
* keep renames and concurrent inserts, and readdir(2) away).
|
||||||
|
*/
|
||||||
|
void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
|
||||||
|
{
|
||||||
|
BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
|
||||||
|
BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
|
||||||
|
|
||||||
|
spin_lock(&dcache_lock);
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
|
memcpy((unsigned char *)dentry->d_name.name, name->name, name->len);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
spin_unlock(&dcache_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dentry_update_name_case);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When switching names, the actual string doesn't strictly have to
|
* When switching names, the actual string doesn't strictly have to
|
||||||
* be preserved in the target - because we're dropping the target
|
* be preserved in the target - because we're dropping the target
|
||||||
|
|
|
@ -611,35 +611,12 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
|
||||||
shrink_dcache_parent(newdent);
|
shrink_dcache_parent(newdent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is not as dangerous as it looks. NetWare's OS2 namespace is
|
* NetWare's OS2 namespace is case preserving yet case
|
||||||
* case preserving yet case insensitive. So we update dentry's name
|
* insensitive. So we update dentry's name as received from
|
||||||
* as received from server. We found dentry via d_lookup with our
|
* server. Parent dir's i_mutex is locked because we're in
|
||||||
* hash, so we know that hash does not change, and so replacing name
|
* readdir.
|
||||||
* should be reasonably safe.
|
|
||||||
*/
|
*/
|
||||||
if (qname.len == newdent->d_name.len &&
|
dentry_update_name_case(newdent, &qname);
|
||||||
memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) {
|
|
||||||
struct inode *inode = newdent->d_inode;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inside ncpfs all uses of d_name are either for debugging,
|
|
||||||
* or on functions which acquire inode mutex (mknod, creat,
|
|
||||||
* lookup). So grab i_mutex here, to be sure. d_path
|
|
||||||
* uses dcache_lock when generating path, so we should too.
|
|
||||||
* And finally d_compare is protected by dentry's d_lock, so
|
|
||||||
* here we go.
|
|
||||||
*/
|
|
||||||
if (inode)
|
|
||||||
mutex_lock(&inode->i_mutex);
|
|
||||||
spin_lock(&dcache_lock);
|
|
||||||
spin_lock(&newdent->d_lock);
|
|
||||||
memcpy((char *) newdent->d_name.name, qname.name,
|
|
||||||
newdent->d_name.len);
|
|
||||||
spin_unlock(&newdent->d_lock);
|
|
||||||
spin_unlock(&dcache_lock);
|
|
||||||
if (inode)
|
|
||||||
mutex_unlock(&inode->i_mutex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newdent->d_inode) {
|
if (!newdent->d_inode) {
|
||||||
|
@ -657,7 +634,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
|
||||||
} else {
|
} else {
|
||||||
struct inode *inode = newdent->d_inode;
|
struct inode *inode = newdent->d_inode;
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
|
||||||
ncp_update_inode2(inode, entry);
|
ncp_update_inode2(inode, entry);
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,6 +290,8 @@ static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *in
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void dentry_update_name_case(struct dentry *, struct qstr *);
|
||||||
|
|
||||||
/* used for rename() and baskets */
|
/* used for rename() and baskets */
|
||||||
extern void d_move(struct dentry *, struct dentry *);
|
extern void d_move(struct dentry *, struct dentry *);
|
||||||
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
||||||
|
|
Loading…
Reference in a new issue