|
@@ -712,11 +712,14 @@ error:
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * v9fs_vfs_create - VFS hook to create files
|
|
|
+ * v9fs_vfs_create - VFS hook to create a regular file
|
|
|
+ *
|
|
|
+ * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called
|
|
|
+ * for mknod(2).
|
|
|
+ *
|
|
|
* @dir: directory inode that is being created
|
|
|
* @dentry: dentry that is being deleted
|
|
|
* @mode: create permissions
|
|
|
- * @nd: path information
|
|
|
*
|
|
|
*/
|
|
|
|
|
@@ -724,76 +727,19 @@ static int
|
|
|
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
struct nameidata *nd)
|
|
|
{
|
|
|
- int err;
|
|
|
- u32 perm;
|
|
|
- int flags;
|
|
|
- struct file *filp;
|
|
|
- struct v9fs_inode *v9inode;
|
|
|
- struct v9fs_session_info *v9ses;
|
|
|
- struct p9_fid *fid, *inode_fid;
|
|
|
-
|
|
|
- err = 0;
|
|
|
- fid = NULL;
|
|
|
- v9ses = v9fs_inode2v9ses(dir);
|
|
|
- perm = unixmode2p9mode(v9ses, mode);
|
|
|
- if (nd)
|
|
|
- flags = nd->intent.open.flags;
|
|
|
- else
|
|
|
- flags = O_RDWR;
|
|
|
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
|
|
|
+ u32 perm = unixmode2p9mode(v9ses, mode);
|
|
|
+ struct p9_fid *fid;
|
|
|
|
|
|
- fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
|
|
- v9fs_uflags2omode(flags,
|
|
|
- v9fs_proto_dotu(v9ses)));
|
|
|
- if (IS_ERR(fid)) {
|
|
|
- err = PTR_ERR(fid);
|
|
|
- fid = NULL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ /* P9_OEXCL? */
|
|
|
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
|
|
|
+ if (IS_ERR(fid))
|
|
|
+ return PTR_ERR(fid);
|
|
|
|
|
|
v9fs_invalidate_inode_attr(dir);
|
|
|
- /* if we are opening a file, assign the open fid to the file */
|
|
|
- if (nd) {
|
|
|
- v9inode = V9FS_I(dentry->d_inode);
|
|
|
- mutex_lock(&v9inode->v_mutex);
|
|
|
- if (v9ses->cache && !v9inode->writeback_fid &&
|
|
|
- ((flags & O_ACCMODE) != O_RDONLY)) {
|
|
|
- /*
|
|
|
- * clone a fid and add it to writeback_fid
|
|
|
- * we do it during open time instead of
|
|
|
- * page dirty time via write_begin/page_mkwrite
|
|
|
- * because we want write after unlink usecase
|
|
|
- * to work.
|
|
|
- */
|
|
|
- inode_fid = v9fs_writeback_fid(dentry);
|
|
|
- if (IS_ERR(inode_fid)) {
|
|
|
- err = PTR_ERR(inode_fid);
|
|
|
- mutex_unlock(&v9inode->v_mutex);
|
|
|
- goto error;
|
|
|
- }
|
|
|
- v9inode->writeback_fid = (void *) inode_fid;
|
|
|
- }
|
|
|
- mutex_unlock(&v9inode->v_mutex);
|
|
|
- filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
|
|
- if (IS_ERR(filp)) {
|
|
|
- err = PTR_ERR(filp);
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- filp->private_data = fid;
|
|
|
-#ifdef CONFIG_9P_FSCACHE
|
|
|
- if (v9ses->cache)
|
|
|
- v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
|
|
|
-#endif
|
|
|
- } else
|
|
|
- p9_client_clunk(fid);
|
|
|
+ p9_client_clunk(fid);
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-error:
|
|
|
- if (fid)
|
|
|
- p9_client_clunk(fid);
|
|
|
-
|
|
|
- return err;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -910,6 +856,93 @@ error:
|
|
|
return ERR_PTR(result);
|
|
|
}
|
|
|
|
|
|
+static struct file *
|
|
|
+v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct opendata *od, unsigned flags, umode_t mode,
|
|
|
+ bool *created)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ u32 perm;
|
|
|
+ struct file *filp;
|
|
|
+ struct v9fs_inode *v9inode;
|
|
|
+ struct v9fs_session_info *v9ses;
|
|
|
+ struct p9_fid *fid, *inode_fid;
|
|
|
+ struct dentry *res = NULL;
|
|
|
+
|
|
|
+ if (d_unhashed(dentry)) {
|
|
|
+ res = v9fs_vfs_lookup(dir, dentry, NULL);
|
|
|
+ if (IS_ERR(res))
|
|
|
+ return ERR_CAST(res);
|
|
|
+
|
|
|
+ if (res)
|
|
|
+ dentry = res;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Only creates */
|
|
|
+ if (!(flags & O_CREAT) || dentry->d_inode) {
|
|
|
+ finish_no_open(od, res);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = 0;
|
|
|
+ fid = NULL;
|
|
|
+ v9ses = v9fs_inode2v9ses(dir);
|
|
|
+ perm = unixmode2p9mode(v9ses, mode);
|
|
|
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
|
|
+ v9fs_uflags2omode(flags,
|
|
|
+ v9fs_proto_dotu(v9ses)));
|
|
|
+ if (IS_ERR(fid)) {
|
|
|
+ err = PTR_ERR(fid);
|
|
|
+ fid = NULL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ v9fs_invalidate_inode_attr(dir);
|
|
|
+ v9inode = V9FS_I(dentry->d_inode);
|
|
|
+ mutex_lock(&v9inode->v_mutex);
|
|
|
+ if (v9ses->cache && !v9inode->writeback_fid &&
|
|
|
+ ((flags & O_ACCMODE) != O_RDONLY)) {
|
|
|
+ /*
|
|
|
+ * clone a fid and add it to writeback_fid
|
|
|
+ * we do it during open time instead of
|
|
|
+ * page dirty time via write_begin/page_mkwrite
|
|
|
+ * because we want write after unlink usecase
|
|
|
+ * to work.
|
|
|
+ */
|
|
|
+ inode_fid = v9fs_writeback_fid(dentry);
|
|
|
+ if (IS_ERR(inode_fid)) {
|
|
|
+ err = PTR_ERR(inode_fid);
|
|
|
+ mutex_unlock(&v9inode->v_mutex);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ v9inode->writeback_fid = (void *) inode_fid;
|
|
|
+ }
|
|
|
+ mutex_unlock(&v9inode->v_mutex);
|
|
|
+ filp = finish_open(od, dentry, generic_file_open);
|
|
|
+ if (IS_ERR(filp)) {
|
|
|
+ err = PTR_ERR(filp);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ filp->private_data = fid;
|
|
|
+#ifdef CONFIG_9P_FSCACHE
|
|
|
+ if (v9ses->cache)
|
|
|
+ v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
|
|
|
+#endif
|
|
|
+
|
|
|
+ *created = true;
|
|
|
+out:
|
|
|
+ dput(res);
|
|
|
+ return filp;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (fid)
|
|
|
+ p9_client_clunk(fid);
|
|
|
+
|
|
|
+ filp = ERR_PTR(err);
|
|
|
+ goto out;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* v9fs_vfs_unlink - VFS unlink hook to delete an inode
|
|
|
* @i: inode that is being unlinked
|
|
@@ -1488,6 +1521,7 @@ out:
|
|
|
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
|
|
.create = v9fs_vfs_create,
|
|
|
.lookup = v9fs_vfs_lookup,
|
|
|
+ .atomic_open = v9fs_vfs_atomic_open,
|
|
|
.symlink = v9fs_vfs_symlink,
|
|
|
.link = v9fs_vfs_link,
|
|
|
.unlink = v9fs_vfs_unlink,
|
|
@@ -1502,6 +1536,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
|
|
static const struct inode_operations v9fs_dir_inode_operations = {
|
|
|
.create = v9fs_vfs_create,
|
|
|
.lookup = v9fs_vfs_lookup,
|
|
|
+ .atomic_open = v9fs_vfs_atomic_open,
|
|
|
.unlink = v9fs_vfs_unlink,
|
|
|
.mkdir = v9fs_vfs_mkdir,
|
|
|
.rmdir = v9fs_vfs_rmdir,
|