/* Calls cr_mknod and then opens with the given flags, returning a (struct file *) */ struct file * cr_filp_mknod(cr_errbuf_t *eb, const char *name, int mode, int flags, unsigned long unlinked_id) { struct nameidata nd; struct dentry * dentry; struct file *filp; /* mknod */ dentry = cr_mknod(eb, &nd, name, mode, unlinked_id); if (IS_ERR(dentry)) { CR_KTRACE_UNEXPECTED("Failed to recreate %sfilesystem object %s, err=%d.", unlinked_id?"unlinked ":"", name, (int)PTR_ERR(dentry)); filp = (struct file *)dentry; goto out; } /* now open it */ filp = cr_dentry_open(dget(dentry), mntget(nd.nd_mnt), flags); if (IS_ERR(filp)) { CR_ERR_EB(eb, "Failed to reopen %sfilesystem object %s, err=%d.", unlinked_id?"unlinked ":"", name, (int)PTR_ERR(dentry)); goto out_dput; } /* check that we actually got the expected type */ if ((mode ^ filp->f_dentry->d_inode->i_mode) & S_IFMT) { CR_ERR_EB(eb, "Type conflict when recreating %sfilesystem object %s.", unlinked_id?"unlinked ":"", name); fput(filp); filp = ERR_PTR(-EEXIST); goto out_dput; } out_dput: dput(dentry); cr_path_release(&nd); out: return filp; }
/* Calls cr_mknod and then opens with the given flags, returning a (struct file *) */ struct file * cr_filp_mknod(cr_errbuf_t *eb, const char *name, int mode, int flags, unsigned long unlinked_id) { struct path path; struct file *filp; int err; /* mknod */ err = cr_mknod(eb, &path, name, mode, unlinked_id); if (err) { CR_KTRACE_UNEXPECTED("Failed to recreate %sfilesystem object %s, err=%d.", unlinked_id?"unlinked ":"", name, err); filp = (struct file *)ERR_PTR(err); goto out; } /* now open it */ path_get(&path); filp = cr_dentry_open_perm(&path, flags); if (IS_ERR(filp)) { CR_ERR_EB(eb, "Failed to reopen %sfilesystem object %s, err=%d.", unlinked_id?"unlinked ":"", name, (int)PTR_ERR(filp)); goto out_put; } /* check that we actually got the expected type */ if ((mode ^ filp->f_dentry->d_inode->i_mode) & S_IFMT) { CR_ERR_EB(eb, "Type conflict when recreating %sfilesystem object %s.", unlinked_id?"unlinked ":"", name); fput(filp); filp = ERR_PTR(-EEXIST); } out_put: path_put(&path); out: return filp; }
/* cr_mknod - based on linux/fs/namei.c:sys_mknod * * Creates regular files or fifos (no devices) making them anonymous (unlinked) * if desired. * Returns a dentry for the resulting filesystem objects, and the corresponding * vfsmnt can be obtained in nd->mnt. Together these two can be passed * to dentry_open() or cr_dentry_open(), even for an unlinked inode. * In the event of an error, no dput() or cr_path_release() is required, * otherwise they are. * * In the event that an object exists with the given name, it will be * check for the proper mode prior to return, yielding -EEXIST on conflict. */ struct dentry * cr_mknod(cr_errbuf_t *eb, struct nameidata *nd, const char *name, int mode, unsigned long unlinked_id) { struct dentry * dentry; int err; if (unlinked_id) { /* Generate a replacement name which we will use instead of the original one. */ name = cr_anonymous_rename(eb, name, unlinked_id); if (!name) { CR_ERR_EB(eb, "cr_mknod - failed to rename unlinked object"); err = -ENOMEM; goto out; } } /* Prior to 2.6.26, lookup_create() would return an exisiting dentry. * Since 2.6.26, it returns -EEXIST if the dentry exists. So, we first * check for an existing dentry. For older kernels this is not required, * but is still correct. */ err = path_lookup(name, LOOKUP_FOLLOW, nd); if (!err) { dentry = dget(nd->nd_dentry); err = -EEXIST; /* Forces mode validation below */ goto have_it; } err = path_lookup(name, LOOKUP_PARENT, nd); if (err) { CR_KTRACE_UNEXPECTED("Couldn't path_lookup for mknod %s. err=%d.", name, err); goto out_free; } dentry = cr_lookup_create(nd, 0); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); CR_KTRACE_UNEXPECTED("Couldn't lookup_create for mknod %s. err=%d.", name, err); goto out_release; } switch (mode & S_IFMT) { case S_IFREG: err = vfs_create(nd->nd_dentry->d_inode, dentry, mode, nd); break; case S_IFIFO: err = cr_vfs_mknod(nd->nd_dentry->d_inode, dentry, nd->nd_mnt, mode, 0 /* ignored */); break; default: CR_ERR_EB(eb, "Unknown/invalid type %d passed to cr_mknod %s.", (mode&S_IFMT), name); err = -EINVAL; } if (unlinked_id && !err) { /* Note that we don't unlink if we failed to create */ dget(dentry); /* ensure unlink doesn't destroy the dentry */ /* Note possibility of silent failure here: */ (void)cr_vfs_unlink(nd->nd_dentry->d_inode, dentry, nd->nd_mnt); dput(dentry); } cr_inode_unlock(nd->nd_dentry->d_inode); have_it: if ((err == -EEXIST) && !((dentry->d_inode->i_mode ^ mode) & S_IFMT)) { /* We fall through and return the dentry */ } else if (err) { CR_KTRACE_UNEXPECTED("Couldn't cr_mknod %s. err=%d.", name, err); goto out_put; } if (unlinked_id) { __putname(name); } return dentry; out_put: dput(dentry); out_release: cr_path_release(nd); out_free: if (unlinked_id) { __putname(name); } out: return (struct dentry *)ERR_PTR(err); }