|
@@ -42,6 +42,25 @@
|
|
|
|
|
|
#define NFSDBG_FACILITY NFSDBG_CLIENT
|
|
|
|
|
|
+/*
|
|
|
+ * Set the superblock root dentry.
|
|
|
+ * Note that this function frees the inode in case of error.
|
|
|
+ */
|
|
|
+static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode)
|
|
|
+{
|
|
|
+ /* The mntroot acts as the dummy root dentry for this superblock */
|
|
|
+ if (sb->s_root == NULL) {
|
|
|
+ sb->s_root = d_alloc_root(inode);
|
|
|
+ if (sb->s_root == NULL) {
|
|
|
+ iput(inode);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ /* Circumvent igrab(): we know the inode is not being freed */
|
|
|
+ atomic_inc(&inode->i_count);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* get an NFS2/NFS3 root dentry from the root filehandle
|
|
|
*/
|
|
@@ -54,33 +73,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|
|
struct inode *inode;
|
|
|
int error;
|
|
|
|
|
|
- /* create a dummy root dentry with dummy inode for this superblock */
|
|
|
- if (!sb->s_root) {
|
|
|
- struct nfs_fh dummyfh;
|
|
|
- struct dentry *root;
|
|
|
- struct inode *iroot;
|
|
|
-
|
|
|
- memset(&dummyfh, 0, sizeof(dummyfh));
|
|
|
- memset(&fattr, 0, sizeof(fattr));
|
|
|
- nfs_fattr_init(&fattr);
|
|
|
- fattr.valid = NFS_ATTR_FATTR;
|
|
|
- fattr.type = NFDIR;
|
|
|
- fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
|
|
|
- fattr.nlink = 2;
|
|
|
-
|
|
|
- iroot = nfs_fhget(sb, &dummyfh, &fattr);
|
|
|
- if (IS_ERR(iroot))
|
|
|
- return ERR_PTR(PTR_ERR(iroot));
|
|
|
-
|
|
|
- root = d_alloc_root(iroot);
|
|
|
- if (!root) {
|
|
|
- iput(iroot);
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
-
|
|
|
- sb->s_root = root;
|
|
|
- }
|
|
|
-
|
|
|
/* get the actual root for this mount */
|
|
|
fsinfo.fattr = &fattr;
|
|
|
|
|
@@ -96,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|
|
return ERR_PTR(PTR_ERR(inode));
|
|
|
}
|
|
|
|
|
|
+ error = nfs_superblock_set_dummy_root(sb, inode);
|
|
|
+ if (error != 0)
|
|
|
+ return ERR_PTR(error);
|
|
|
+
|
|
|
/* root dentries normally start off anonymous and get spliced in later
|
|
|
* if the dentry tree reaches them; however if the dentry already
|
|
|
* exists, we'll pick it up at this point and use it as the root
|
|
@@ -241,33 +237,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|
|
|
|
|
dprintk("--> nfs4_get_root()\n");
|
|
|
|
|
|
- /* create a dummy root dentry with dummy inode for this superblock */
|
|
|
- if (!sb->s_root) {
|
|
|
- struct nfs_fh dummyfh;
|
|
|
- struct dentry *root;
|
|
|
- struct inode *iroot;
|
|
|
-
|
|
|
- memset(&dummyfh, 0, sizeof(dummyfh));
|
|
|
- memset(&fattr, 0, sizeof(fattr));
|
|
|
- nfs_fattr_init(&fattr);
|
|
|
- fattr.valid = NFS_ATTR_FATTR;
|
|
|
- fattr.type = NFDIR;
|
|
|
- fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
|
|
|
- fattr.nlink = 2;
|
|
|
-
|
|
|
- iroot = nfs_fhget(sb, &dummyfh, &fattr);
|
|
|
- if (IS_ERR(iroot))
|
|
|
- return ERR_PTR(PTR_ERR(iroot));
|
|
|
-
|
|
|
- root = d_alloc_root(iroot);
|
|
|
- if (!root) {
|
|
|
- iput(iroot);
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
-
|
|
|
- sb->s_root = root;
|
|
|
- }
|
|
|
-
|
|
|
/* get the info about the server and filesystem */
|
|
|
error = nfs4_server_capabilities(server, mntfh);
|
|
|
if (error < 0) {
|
|
@@ -289,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|
|
return ERR_PTR(PTR_ERR(inode));
|
|
|
}
|
|
|
|
|
|
+ error = nfs_superblock_set_dummy_root(sb, inode);
|
|
|
+ if (error != 0)
|
|
|
+ return ERR_PTR(error);
|
|
|
+
|
|
|
/* root dentries normally start off anonymous and get spliced in later
|
|
|
* if the dentry tree reaches them; however if the dentry already
|
|
|
* exists, we'll pick it up at this point and use it as the root
|