static void wrapfs_d_release(struct dentry *dentry)
{
- /* release and reset the lower paths */
- wrapfs_put_reset_lower_path(dentry);
- free_dentry_private_data(dentry);
+ /*
+ * It is possible that the dentry private data is NULL in case we
+ * ran out of memory while initializing it in
+ * new_dentry_private_data. So check for NULL before attempting to
+ * release resources.
+ */
+ if (WRAPFS_D(dentry)) {
+ /* release and reset the lower paths */
+ wrapfs_put_reset_lower_path(dentry);
+ free_dentry_private_data(dentry);
+ }
return;
}
if (!WRAPFS_SB(sb)) {
printk(KERN_CRIT "wrapfs: read_super: out of memory\n");
err = -ENOMEM;
- goto out_free;
+ goto out_pput;
}
/* set the lower superblock field of upper superblock */
inode = wrapfs_iget(sb, d_inode(lower_path.dentry));
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
- goto out_sput;
+ goto out_pput;
}
sb->s_root = d_make_root(inode);
if (!sb->s_root) {
err = -ENOMEM;
- goto out_iput;
+ goto out_pput;
}
d_set_d_op(sb->s_root, &wrapfs_dops);
sb->s_root->d_fsdata = NULL;
err = new_dentry_private_data(sb->s_root);
if (err)
- goto out_freeroot;
+ goto out_pput;
/* if get here: cannot have error */
dev_name, lower_sb->s_type->name);
goto out; /* all is well */
- /* no longer needed: free_dentry_private_data(sb->s_root); */
-out_freeroot:
- dput(sb->s_root);
-out_iput:
- iput(inode);
-out_sput:
- /* drop refs we took earlier */
- atomic_dec(&lower_sb->s_active);
- kfree(WRAPFS_SB(sb));
- sb->s_fs_info = NULL;
-out_free:
+ /*
+ * path_put is the only resource we need to free if an error occurred
+ * because returning an error from this function will cause
+ * generic_shutdown_super to be called, which will call
+ * wrapfs_put_super, and that function will release any other
+ * resources we took.
+ */
+out_pput:
path_put(&lower_path);
-
out:
return err;
}