diff options
author | Chunwei Chen <[email protected]> | 2016-01-26 12:29:46 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-11-04 10:46:40 -0700 |
commit | ace1eae84cca8579596f46262d99df19f6d7e963 (patch) | |
tree | 22e2bf44dfc906cf6cb75567d993a86f64bf1ef8 /module/zfs/zpl_inode.c | |
parent | 987014903f9d36783547188b6ad00f01d9a076bd (diff) |
Add support for O_TMPFILE
Linux 3.11 add O_TMPFILE to open(2), which allow creating an unlinked file on
supported filesystem. It's basically doing open(2) and unlink(2) atomically.
The filesystem support is added through i_op->tmpfile. We basically copy the
create operation except we get rid of the link and name related stuff and add
the new node to unlinked set.
We also add support for linkat(2) to link tmpfile. However, since all previous
file operation will skip ZIL, we force a txg_wait_synced to make sure we are
sync safe.
Signed-off-by: Chunwei Chen <[email protected]>
Diffstat (limited to 'module/zfs/zpl_inode.c')
-rw-r--r-- | module/zfs/zpl_inode.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c index b8adda7a1..b1f9b1f4e 100644 --- a/module/zfs/zpl_inode.c +++ b/module/zfs/zpl_inode.c @@ -214,6 +214,45 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, zpl_umode_t mode, return (error); } +#ifdef HAVE_TMPFILE +static int +zpl_tmpfile(struct inode *dir, struct dentry *dentry, zpl_umode_t mode) +{ + cred_t *cr = CRED(); + struct inode *ip; + vattr_t *vap; + int error; + fstrans_cookie_t cookie; + + crhold(cr); + vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); + zpl_vap_init(vap, dir, mode, cr); + + cookie = spl_fstrans_mark(); + error = -zfs_tmpfile(dir, vap, 0, mode, &ip, cr, 0, NULL); + if (error == 0) { + /* d_tmpfile will do drop_nlink, so we should set it first */ + set_nlink(ip, 1); + d_tmpfile(dentry, ip); + + error = zpl_xattr_security_init(ip, dir, &dentry->d_name); + if (error == 0) + error = zpl_init_acl(ip, dir); + /* + * don't need to handle error here, file is already in + * unlinked set. + */ + } + + spl_fstrans_unmark(cookie); + kmem_free(vap, sizeof (vattr_t)); + crfree(cr); + ASSERT3S(error, <=, 0); + + return (error); +} +#endif + static int zpl_unlink(struct inode *dir, struct dentry *dentry) { @@ -701,6 +740,9 @@ const struct inode_operations zpl_dir_inode_operations = { #else .rename = zpl_rename, #endif +#ifdef HAVE_TMPFILE + .tmpfile = zpl_tmpfile, +#endif .setattr = zpl_setattr, .getattr = zpl_getattr, #ifdef HAVE_GENERIC_SETXATTR |