Skip to content

Commit 2b10826

Browse files
fs/ntfs3: atomic_open implementation
Added ntfs_atomic_open function. Relaxed locking in ntfs_create_inode. Signed-off-by: Konstantin Komarov <[email protected]>
1 parent 07f4aa9 commit 2b10826

File tree

2 files changed

+120
-4
lines changed

2 files changed

+120
-4
lines changed

fs/ntfs3/inode.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,18 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
11841184
return ERR_PTR(err);
11851185
}
11861186

1187+
/*
1188+
* ntfs_create_inode
1189+
*
1190+
* Helper function for:
1191+
* - ntfs_create
1192+
* - ntfs_mknod
1193+
* - ntfs_symlink
1194+
* - ntfs_mkdir
1195+
* - ntfs_atomic_open
1196+
*
1197+
* NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked
1198+
*/
11871199
struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
11881200
struct inode *dir, struct dentry *dentry,
11891201
const struct cpu_str *uni, umode_t mode,
@@ -1213,7 +1225,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
12131225
struct REPARSE_DATA_BUFFER *rp = NULL;
12141226
bool rp_inserted = false;
12151227

1216-
ni_lock_dir(dir_ni);
1228+
if (!fnd)
1229+
ni_lock_dir(dir_ni);
12171230

12181231
dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
12191232
if (!dir_root) {
@@ -1583,7 +1596,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
15831596
goto out6;
15841597

15851598
/* Unlock parent directory before ntfs_init_acl. */
1586-
ni_unlock(dir_ni);
1599+
if (!fnd)
1600+
ni_unlock(dir_ni);
15871601

15881602
inode->i_generation = le16_to_cpu(rec->seq);
15891603

@@ -1643,7 +1657,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
16431657
out7:
16441658

16451659
/* Undo 'indx_insert_entry'. */
1646-
ni_lock_dir(dir_ni);
1660+
if (!fnd)
1661+
ni_lock_dir(dir_ni);
16471662
indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
16481663
le16_to_cpu(new_de->key_size), sbi);
16491664
/* ni_unlock(dir_ni); will be called later. */
@@ -1671,7 +1686,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
16711686

16721687
out1:
16731688
if (err) {
1674-
ni_unlock(dir_ni);
1689+
if (!fnd)
1690+
ni_unlock(dir_ni);
16751691
return ERR_PTR(err);
16761692
}
16771693

fs/ntfs3/namei.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/fs.h>
99
#include <linux/nls.h>
1010
#include <linux/ctype.h>
11+
#include <linux/posix_acl.h>
1112

1213
#include "debug.h"
1314
#include "ntfs.h"
@@ -334,6 +335,104 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
334335
return err;
335336
}
336337

338+
/*
339+
* ntfs_atomic_open
340+
*
341+
* inode_operations::atomic_open
342+
*/
343+
static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
344+
struct file *file, u32 flags, umode_t mode)
345+
{
346+
int err;
347+
struct inode *inode;
348+
struct ntfs_fnd *fnd = NULL;
349+
struct ntfs_inode *ni = ntfs_i(dir);
350+
struct dentry *d = NULL;
351+
struct cpu_str *uni = __getname();
352+
bool locked = false;
353+
354+
if (!uni)
355+
return -ENOMEM;
356+
357+
err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name,
358+
dentry->d_name.len, uni, NTFS_NAME_LEN,
359+
UTF16_HOST_ENDIAN);
360+
if (err < 0)
361+
goto out;
362+
363+
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
364+
if (IS_POSIXACL(dir)) {
365+
/*
366+
* Load in cache current acl to avoid ni_lock(dir):
367+
* ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
368+
* ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
369+
*/
370+
struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);
371+
372+
if (IS_ERR(p)) {
373+
err = PTR_ERR(p);
374+
goto out;
375+
}
376+
posix_acl_release(p);
377+
}
378+
#endif
379+
380+
if (d_in_lookup(dentry)) {
381+
ni_lock_dir(ni);
382+
locked = true;
383+
fnd = fnd_get();
384+
if (!fnd) {
385+
err = -ENOMEM;
386+
goto out1;
387+
}
388+
389+
d = d_splice_alias(dir_search_u(dir, uni, fnd), dentry);
390+
if (IS_ERR(d)) {
391+
err = PTR_ERR(d);
392+
d = NULL;
393+
goto out2;
394+
}
395+
396+
if (d)
397+
dentry = d;
398+
}
399+
400+
if (!(flags & O_CREAT) || d_really_is_positive(dentry)) {
401+
err = finish_no_open(file, d);
402+
goto out2;
403+
}
404+
405+
file->f_mode |= FMODE_CREATED;
406+
407+
/*
408+
* fnd contains tree's path to insert to.
409+
* If fnd is not NULL then dir is locked.
410+
*/
411+
412+
/*
413+
* Unfortunately I don't know how to get here correct 'struct nameidata *nd'
414+
* or 'struct user_namespace *mnt_userns'.
415+
* See atomic_open in fs/namei.c.
416+
* This is why xfstest/633 failed.
417+
* Looks like ntfs_atomic_open must accept 'struct user_namespace *mnt_userns' as argument.
418+
*/
419+
420+
inode = ntfs_create_inode(&init_user_ns, dir, dentry, uni, mode, 0,
421+
NULL, 0, fnd);
422+
err = IS_ERR(inode) ? PTR_ERR(inode)
423+
: finish_open(file, dentry, ntfs_file_open);
424+
dput(d);
425+
426+
out2:
427+
fnd_put(fnd);
428+
out1:
429+
if (locked)
430+
ni_unlock(ni);
431+
out:
432+
__putname(uni);
433+
return err;
434+
}
435+
337436
struct dentry *ntfs3_get_parent(struct dentry *child)
338437
{
339438
struct inode *inode = d_inode(child);
@@ -500,6 +599,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
500599
.setattr = ntfs3_setattr,
501600
.getattr = ntfs_getattr,
502601
.listxattr = ntfs_listxattr,
602+
.atomic_open = ntfs_atomic_open,
503603
.fiemap = ntfs_fiemap,
504604
};
505605

0 commit comments

Comments
 (0)