Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kill d_instantiate_no_diralias()

The only user is fuse_create_new_entry(), and there it's used to
mitigate the same mkdir/open-by-handle race as in nfs_mkdir().
The same solution applies - unhash the mkdir argument, then
call d_splice_alias() and if that returns a reference to preexisting
alias, dput() and report success. ->mkdir() argument left unhashed
negative with the preexisting alias moved in the right place is just
fine from the ->mkdir() callers point of view.

Cc: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro c971e6a0 b0c6108e

+11 -32
-27
fs/dcache.c
··· 1899 1899 } 1900 1900 EXPORT_SYMBOL(d_instantiate_new); 1901 1901 1902 - /** 1903 - * d_instantiate_no_diralias - instantiate a non-aliased dentry 1904 - * @entry: dentry to complete 1905 - * @inode: inode to attach to this dentry 1906 - * 1907 - * Fill in inode information in the entry. If a directory alias is found, then 1908 - * return an error (and drop inode). Together with d_materialise_unique() this 1909 - * guarantees that a directory inode may never have more than one alias. 1910 - */ 1911 - int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode) 1912 - { 1913 - BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); 1914 - 1915 - security_d_instantiate(entry, inode); 1916 - spin_lock(&inode->i_lock); 1917 - if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) { 1918 - spin_unlock(&inode->i_lock); 1919 - iput(inode); 1920 - return -EBUSY; 1921 - } 1922 - __d_instantiate(entry, inode); 1923 - spin_unlock(&inode->i_lock); 1924 - 1925 - return 0; 1926 - } 1927 - EXPORT_SYMBOL(d_instantiate_no_diralias); 1928 - 1929 1902 struct dentry *d_make_root(struct inode *root_inode) 1930 1903 { 1931 1904 struct dentry *res = NULL;
+11 -4
fs/fuse/dir.c
··· 539 539 { 540 540 struct fuse_entry_out outarg; 541 541 struct inode *inode; 542 + struct dentry *d; 542 543 int err; 543 544 struct fuse_forget_link *forget; 544 545 ··· 571 570 } 572 571 kfree(forget); 573 572 574 - err = d_instantiate_no_diralias(entry, inode); 575 - if (err) 576 - return err; 573 + d_drop(entry); 574 + d = d_splice_alias(inode, entry); 575 + if (IS_ERR(d)) 576 + return PTR_ERR(d); 577 577 578 - fuse_change_entry_timeout(entry, &outarg); 578 + if (d) { 579 + fuse_change_entry_timeout(d, &outarg); 580 + dput(d); 581 + } else { 582 + fuse_change_entry_timeout(entry, &outarg); 583 + } 579 584 fuse_invalidate_attr(dir); 580 585 return 0; 581 586
-1
include/linux/dcache.h
··· 227 227 extern void d_instantiate_new(struct dentry *, struct inode *); 228 228 extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); 229 229 extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *); 230 - extern int d_instantiate_no_diralias(struct dentry *, struct inode *); 231 230 extern void __d_drop(struct dentry *dentry); 232 231 extern void d_drop(struct dentry *dentry); 233 232 extern void d_delete(struct dentry *);