aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/smbfs/cache.c4
-rw-r--r--fs/dcache.c27
-rw-r--r--fs/ncpfs/dir.c35
-rw-r--r--include/linux/dcache.h2
4 files changed, 37 insertions, 31 deletions
diff --git a/drivers/staging/smbfs/cache.c b/drivers/staging/smbfs/cache.c
index dbb98658148b..dbd2e1df3ba9 100644
--- a/drivers/staging/smbfs/cache.c
+++ b/drivers/staging/smbfs/cache.c
@@ -145,8 +145,8 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
145 goto end_advance; 145 goto end_advance;
146 } else { 146 } else {
147 hashed = 1; 147 hashed = 1;
148 memcpy((char *) newdent->d_name.name, qname->name, 148 /* dir i_mutex is locked because we're in readdir */
149 newdent->d_name.len); 149 dentry_update_name_case(newdent, qname);
150 } 150 }
151 151
152 if (!newdent->d_inode) { 152 if (!newdent->d_inode) {
diff --git a/fs/dcache.c b/fs/dcache.c
index 6ee6bc40cb63..814e5f491e9c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1589,6 +1589,33 @@ void d_rehash(struct dentry * entry)
1589} 1589}
1590EXPORT_SYMBOL(d_rehash); 1590EXPORT_SYMBOL(d_rehash);
1591 1591
1592/**
1593 * dentry_update_name_case - update case insensitive dentry with a new name
1594 * @dentry: dentry to be updated
1595 * @name: new name
1596 *
1597 * Update a case insensitive dentry with new case of name.
1598 *
1599 * dentry must have been returned by d_lookup with name @name. Old and new
1600 * name lengths must match (ie. no d_compare which allows mismatched name
1601 * lengths).
1602 *
1603 * Parent inode i_mutex must be held over d_lookup and into this call (to
1604 * keep renames and concurrent inserts, and readdir(2) away).
1605 */
1606void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
1607{
1608 BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
1609 BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
1610
1611 spin_lock(&dcache_lock);
1612 spin_lock(&dentry->d_lock);
1613 memcpy((unsigned char *)dentry->d_name.name, name->name, name->len);
1614 spin_unlock(&dentry->d_lock);
1615 spin_unlock(&dcache_lock);
1616}
1617EXPORT_SYMBOL(dentry_update_name_case);
1618
1592/* 1619/*
1593 * When switching names, the actual string doesn't strictly have to 1620 * When switching names, the actual string doesn't strictly have to
1594 * be preserved in the target - because we're dropping the target 1621 * be preserved in the target - because we're dropping the target
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index d6e6453881ce..e80ea4e37c48 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -611,35 +611,12 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
611 shrink_dcache_parent(newdent); 611 shrink_dcache_parent(newdent);
612 612
613 /* 613 /*
614 * It is not as dangerous as it looks. NetWare's OS2 namespace is 614 * NetWare's OS2 namespace is case preserving yet case
615 * case preserving yet case insensitive. So we update dentry's name 615 * insensitive. So we update dentry's name as received from
616 * as received from server. We found dentry via d_lookup with our 616 * server. Parent dir's i_mutex is locked because we're in
617 * hash, so we know that hash does not change, and so replacing name 617 * readdir.
618 * should be reasonably safe.
619 */ 618 */
620 if (qname.len == newdent->d_name.len && 619 dentry_update_name_case(newdent, &qname);
621 memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) {
622 struct inode *inode = newdent->d_inode;
623
624 /*
625 * Inside ncpfs all uses of d_name are either for debugging,
626 * or on functions which acquire inode mutex (mknod, creat,
627 * lookup). So grab i_mutex here, to be sure. d_path
628 * uses dcache_lock when generating path, so we should too.
629 * And finally d_compare is protected by dentry's d_lock, so
630 * here we go.
631 */
632 if (inode)
633 mutex_lock(&inode->i_mutex);
634 spin_lock(&dcache_lock);
635 spin_lock(&newdent->d_lock);
636 memcpy((char *) newdent->d_name.name, qname.name,
637 newdent->d_name.len);
638 spin_unlock(&newdent->d_lock);
639 spin_unlock(&dcache_lock);
640 if (inode)
641 mutex_unlock(&inode->i_mutex);
642 }
643 } 620 }
644 621
645 if (!newdent->d_inode) { 622 if (!newdent->d_inode) {
@@ -657,7 +634,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
657 } else { 634 } else {
658 struct inode *inode = newdent->d_inode; 635 struct inode *inode = newdent->d_inode;
659 636
660 mutex_lock(&inode->i_mutex); 637 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
661 ncp_update_inode2(inode, entry); 638 ncp_update_inode2(inode, entry);
662 mutex_unlock(&inode->i_mutex); 639 mutex_unlock(&inode->i_mutex);
663 } 640 }
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index cbfc9567e4e9..6cdf4995c90a 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -290,6 +290,8 @@ static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *in
290 return res; 290 return res;
291} 291}
292 292
293extern void dentry_update_name_case(struct dentry *, struct qstr *);
294
293/* used for rename() and baskets */ 295/* used for rename() and baskets */
294extern void d_move(struct dentry *, struct dentry *); 296extern void d_move(struct dentry *, struct dentry *);
295extern struct dentry *d_ancestor(struct dentry *, struct dentry *); 297extern struct dentry *d_ancestor(struct dentry *, struct dentry *);