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…
	
	Add table
		Add a link
		
	
		Reference in a new issue