On Mon, Jul 08, 2019 at 11:06:33AM +1000, Stephen Rothwell wrote: > Today's linux-next merge of the vfs tree got a conflict in: > > fs/nfsd/nfsctl.c > > between commits: > > e8a79fb14f6b ("nfsd: add nfsd/clients directory") > > from the nfsd tree and commit: > > 96a374a35f82 ("vfs: Convert nfsctl to use the new mount API") I did a fetch of git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git and looked at the "master" branch and couldn't find that vfs commit. Am I looking in the wrong place? (I'm sure your resolution is fine, I just thought to be careful it might be nice to run some tests on the merge.) --b. > > from the vfs tree. > > I fixed it up (Maybe? see below) and can carry the fix as necessary. > This is now fixed as far as linux-next is concerned, but any non trivial > conflicts should be mentioned to your upstream maintainer when your tree > is submitted for merging. You may also want to consider cooperating > with the maintainer of the conflicting tree to minimise any particularly > complex conflicts. > > -- > Cheers, > Stephen Rothwell > > diff --cc fs/nfsd/nfsctl.c > index 4683ba5c69c7,bbff9c4ac49f..000000000000 > --- a/fs/nfsd/nfsctl.c > +++ b/fs/nfsd/nfsctl.c > @@@ -1149,201 -1148,8 +1150,201 @@@ static ssize_t write_v4_end_grace(struc > * populating the filesystem. > */ > > +/* Basically copying rpc_get_inode. */ > +static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode) > +{ > + struct inode *inode = new_inode(sb); > + if (!inode) > + return NULL; > + /* Following advice from simple_fill_super documentation: */ > + inode->i_ino = iunique(sb, NFSD_MaxReserved); > + inode->i_mode = mode; > + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); > + switch (mode & S_IFMT) { > + case S_IFDIR: > + inode->i_fop = &simple_dir_operations; > + inode->i_op = &simple_dir_inode_operations; > + inc_nlink(inode); > + default: > + break; > + } > + return inode; > +} > + > +static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) > +{ > + struct inode *inode; > + > + inode = nfsd_get_inode(dir->i_sb, mode); > + if (!inode) > + return -ENOMEM; > + d_add(dentry, inode); > + inc_nlink(dir); > + fsnotify_mkdir(dir, dentry); > + return 0; > +} > + > +static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name) > +{ > + struct inode *dir = parent->d_inode; > + struct dentry *dentry; > + int ret = -ENOMEM; > + > + inode_lock(dir); > + dentry = d_alloc_name(parent, name); > + if (!dentry) > + goto out_err; > + ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600); > + if (ret) > + goto out_err; > + if (ncl) { > + d_inode(dentry)->i_private = ncl; > + kref_get(&ncl->cl_ref); > + } > +out: > + inode_unlock(dir); > + return dentry; > +out_err: > + dentry = ERR_PTR(ret); > + goto out; > +} > + > +static void clear_ncl(struct inode *inode) > +{ > + struct nfsdfs_client *ncl = inode->i_private; > + > + inode->i_private = NULL; > + synchronize_rcu(); > + kref_put(&ncl->cl_ref, ncl->cl_release); > +} > + > + > +struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode) > +{ > + struct nfsdfs_client *nc = inode->i_private; > + > + if (nc) > + kref_get(&nc->cl_ref); > + return nc; > +} > + > +struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) > +{ > + struct nfsdfs_client *nc; > + > + rcu_read_lock(); > + nc = __get_nfsdfs_client(inode); > + rcu_read_unlock(); > + return nc; > +} > +/* from __rpc_unlink */ > +static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry) > +{ > + int ret; > + > + clear_ncl(d_inode(dentry)); > + dget(dentry); > + ret = simple_unlink(dir, dentry); > + d_delete(dentry); > + dput(dentry); > + WARN_ON_ONCE(ret); > +} > + > +static void nfsdfs_remove_files(struct dentry *root) > +{ > + struct dentry *dentry, *tmp; > + > + list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) { > + if (!simple_positive(dentry)) { > + WARN_ON_ONCE(1); /* I think this can't happen? */ > + continue; > + } > + nfsdfs_remove_file(d_inode(root), dentry); > + } > +} > + > +/* XXX: cut'n'paste from simple_fill_super; figure out if we could share > + * code instead. */ > +static int nfsdfs_create_files(struct dentry *root, > + const struct tree_descr *files) > +{ > + struct inode *dir = d_inode(root); > + struct inode *inode; > + struct dentry *dentry; > + int i; > + > + inode_lock(dir); > + for (i = 0; files->name && files->name[0]; i++, files++) { > + if (!files->name) > + continue; > + dentry = d_alloc_name(root, files->name); > + if (!dentry) > + goto out; > + inode = nfsd_get_inode(d_inode(root)->i_sb, > + S_IFREG | files->mode); > + if (!inode) { > + dput(dentry); > + goto out; > + } > + inode->i_fop = files->ops; > + inode->i_private = __get_nfsdfs_client(dir); > + d_add(dentry, inode); > + fsnotify_create(dir, dentry); > + } > + inode_unlock(dir); > + return 0; > +out: > + nfsdfs_remove_files(root); > + inode_unlock(dir); > + return -ENOMEM; > +} > + > +/* on success, returns positive number unique to that client. */ > +struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, > + struct nfsdfs_client *ncl, u32 id, > + const struct tree_descr *files) > +{ > + struct dentry *dentry; > + char name[11]; > + int ret; > + > + sprintf(name, "%u", id); > + > + dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); > + if (IS_ERR(dentry)) /* XXX: tossing errors? */ > + return NULL; > + ret = nfsdfs_create_files(dentry, files); > + if (ret) { > + nfsd_client_rmdir(dentry); > + return NULL; > + } > + return dentry; > +} > + > +/* Taken from __rpc_rmdir: */ > +void nfsd_client_rmdir(struct dentry *dentry) > +{ > + struct inode *dir = d_inode(dentry->d_parent); > + struct inode *inode = d_inode(dentry); > + int ret; > + > + inode_lock(dir); > + nfsdfs_remove_files(dentry); > + clear_ncl(inode); > + dget(dentry); > + ret = simple_rmdir(dir, dentry); > + WARN_ON_ONCE(ret); > + d_delete(dentry); > + inode_unlock(dir); > +} > + > - static int nfsd_fill_super(struct super_block * sb, void * data, int silent) > + static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) > { > + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, > + nfsd_net_id); > + struct dentry *dentry; > + int ret; > + > static const struct tree_descr nfsd_files[] = { > [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO}, > [NFSD_Export_features] = {"export_features", > @@@ -1372,23 -1178,33 +1373,39 @@@ > #endif > /* last one */ {""} > }; > - get_net(sb->s_fs_info); > - > - return simple_fill_super(sb, 0x6e667364, nfsd_files); > + ret = simple_fill_super(sb, 0x6e667364, nfsd_files); > + if (ret) > + return ret; > + dentry = nfsd_mkdir(sb->s_root, NULL, "clients"); > + if (IS_ERR(dentry)) > + return PTR_ERR(dentry); > + nn->nfsd_client_dir = dentry; > + return 0; > + } > + > + static int nfsd_fs_get_tree(struct fs_context *fc) > + { > + fc->s_fs_info = get_net(fc->net_ns); > + return vfs_get_super(fc, vfs_get_keyed_super, nfsd_fill_super); > + } > > + static void nfsd_fs_free_fc(struct fs_context *fc) > + { > + if (fc->s_fs_info) > + put_net(fc->s_fs_info); > } > > - static struct dentry *nfsd_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *data) > + static const struct fs_context_operations nfsd_fs_context_ops = { > + .free = nfsd_fs_free_fc, > + .get_tree = nfsd_fs_get_tree, > + }; > + > + static int nfsd_init_fs_context(struct fs_context *fc) > { > - struct net *net = current->nsproxy->net_ns; > - return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super); > + put_user_ns(fc->user_ns); > + fc->user_ns = get_user_ns(fc->net_ns->user_ns); > + fc->ops = &nfsd_fs_context_ops; > + return 0; > } > > static void nfsd_umount(struct super_block *sb)