Skip to content

Commit 2e45092

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: move oplock handling after unlock parent dir
ksmbd should process secound parallel smb2 create request during waiting oplock break ack. parent lock range that is too large in smb2_open() causes smb2_open() to be serialized. Move the oplock handling to the bottom of smb2_open() and make it called after parent unlock. This fixes the failure of smb2.lease.breaking1 testcase. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 4274a9d commit 2e45092

1 file changed

Lines changed: 65 additions & 56 deletions

File tree

fs/smb/server/smb2pdu.c

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,7 +2691,7 @@ int smb2_open(struct ksmbd_work *work)
26912691
*(char *)req->Buffer == '\\') {
26922692
pr_err("not allow directory name included leading slash\n");
26932693
rc = -EINVAL;
2694-
goto err_out1;
2694+
goto err_out2;
26952695
}
26962696

26972697
name = smb2_get_name(req->Buffer,
@@ -2702,36 +2702,36 @@ int smb2_open(struct ksmbd_work *work)
27022702
if (rc != -ENOMEM)
27032703
rc = -ENOENT;
27042704
name = NULL;
2705-
goto err_out1;
2705+
goto err_out2;
27062706
}
27072707

27082708
ksmbd_debug(SMB, "converted name = %s\n", name);
27092709
if (strchr(name, ':')) {
27102710
if (!test_share_config_flag(work->tcon->share_conf,
27112711
KSMBD_SHARE_FLAG_STREAMS)) {
27122712
rc = -EBADF;
2713-
goto err_out1;
2713+
goto err_out2;
27142714
}
27152715
rc = parse_stream_name(name, &stream_name, &s_type);
27162716
if (rc < 0)
2717-
goto err_out1;
2717+
goto err_out2;
27182718
}
27192719

27202720
rc = ksmbd_validate_filename(name);
27212721
if (rc < 0)
2722-
goto err_out1;
2722+
goto err_out2;
27232723

27242724
if (ksmbd_share_veto_filename(share, name)) {
27252725
rc = -ENOENT;
27262726
ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n",
27272727
name);
2728-
goto err_out1;
2728+
goto err_out2;
27292729
}
27302730
} else {
27312731
name = kstrdup("", GFP_KERNEL);
27322732
if (!name) {
27332733
rc = -ENOMEM;
2734-
goto err_out1;
2734+
goto err_out2;
27352735
}
27362736
}
27372737

@@ -2744,14 +2744,14 @@ int smb2_open(struct ksmbd_work *work)
27442744
le32_to_cpu(req->ImpersonationLevel));
27452745
rc = -EIO;
27462746
rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL;
2747-
goto err_out1;
2747+
goto err_out2;
27482748
}
27492749

27502750
if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) {
27512751
pr_err("Invalid create options : 0x%x\n",
27522752
le32_to_cpu(req->CreateOptions));
27532753
rc = -EINVAL;
2754-
goto err_out1;
2754+
goto err_out2;
27552755
} else {
27562756
if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE &&
27572757
req->CreateOptions & FILE_RANDOM_ACCESS_LE)
@@ -2761,13 +2761,13 @@ int smb2_open(struct ksmbd_work *work)
27612761
(FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION |
27622762
FILE_RESERVE_OPFILTER_LE)) {
27632763
rc = -EOPNOTSUPP;
2764-
goto err_out1;
2764+
goto err_out2;
27652765
}
27662766

27672767
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
27682768
if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {
27692769
rc = -EINVAL;
2770-
goto err_out1;
2770+
goto err_out2;
27712771
} else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {
27722772
req->CreateOptions = ~(FILE_NO_COMPRESSION_LE);
27732773
}
@@ -2779,49 +2779,49 @@ int smb2_open(struct ksmbd_work *work)
27792779
pr_err("Invalid create disposition : 0x%x\n",
27802780
le32_to_cpu(req->CreateDisposition));
27812781
rc = -EINVAL;
2782-
goto err_out1;
2782+
goto err_out2;
27832783
}
27842784

27852785
if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) {
27862786
pr_err("Invalid desired access : 0x%x\n",
27872787
le32_to_cpu(req->DesiredAccess));
27882788
rc = -EACCES;
2789-
goto err_out1;
2789+
goto err_out2;
27902790
}
27912791

27922792
if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) {
27932793
pr_err("Invalid file attribute : 0x%x\n",
27942794
le32_to_cpu(req->FileAttributes));
27952795
rc = -EINVAL;
2796-
goto err_out1;
2796+
goto err_out2;
27972797
}
27982798

27992799
if (req->CreateContextsOffset) {
28002800
/* Parse non-durable handle create contexts */
28012801
context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4);
28022802
if (IS_ERR(context)) {
28032803
rc = PTR_ERR(context);
2804-
goto err_out1;
2804+
goto err_out2;
28052805
} else if (context) {
28062806
ea_buf = (struct create_ea_buf_req *)context;
28072807
if (le16_to_cpu(context->DataOffset) +
28082808
le32_to_cpu(context->DataLength) <
28092809
sizeof(struct create_ea_buf_req)) {
28102810
rc = -EINVAL;
2811-
goto err_out1;
2811+
goto err_out2;
28122812
}
28132813
if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) {
28142814
rsp->hdr.Status = STATUS_ACCESS_DENIED;
28152815
rc = -EACCES;
2816-
goto err_out1;
2816+
goto err_out2;
28172817
}
28182818
}
28192819

28202820
context = smb2_find_context_vals(req,
28212821
SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4);
28222822
if (IS_ERR(context)) {
28232823
rc = PTR_ERR(context);
2824-
goto err_out1;
2824+
goto err_out2;
28252825
} else if (context) {
28262826
ksmbd_debug(SMB,
28272827
"get query maximal access context\n");
@@ -2832,27 +2832,27 @@ int smb2_open(struct ksmbd_work *work)
28322832
SMB2_CREATE_TIMEWARP_REQUEST, 4);
28332833
if (IS_ERR(context)) {
28342834
rc = PTR_ERR(context);
2835-
goto err_out1;
2835+
goto err_out2;
28362836
} else if (context) {
28372837
ksmbd_debug(SMB, "get timewarp context\n");
28382838
rc = -EBADF;
2839-
goto err_out1;
2839+
goto err_out2;
28402840
}
28412841

28422842
if (tcon->posix_extensions) {
28432843
context = smb2_find_context_vals(req,
28442844
SMB2_CREATE_TAG_POSIX, 16);
28452845
if (IS_ERR(context)) {
28462846
rc = PTR_ERR(context);
2847-
goto err_out1;
2847+
goto err_out2;
28482848
} else if (context) {
28492849
struct create_posix *posix =
28502850
(struct create_posix *)context;
28512851
if (le16_to_cpu(context->DataOffset) +
28522852
le32_to_cpu(context->DataLength) <
28532853
sizeof(struct create_posix) - 4) {
28542854
rc = -EINVAL;
2855-
goto err_out1;
2855+
goto err_out2;
28562856
}
28572857
ksmbd_debug(SMB, "get posix context\n");
28582858

@@ -2864,7 +2864,7 @@ int smb2_open(struct ksmbd_work *work)
28642864

28652865
if (ksmbd_override_fsids(work)) {
28662866
rc = -ENOMEM;
2867-
goto err_out1;
2867+
goto err_out2;
28682868
}
28692869

28702870
rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,
@@ -3177,11 +3177,6 @@ int smb2_open(struct ksmbd_work *work)
31773177

31783178
fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE |
31793179
FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE));
3180-
if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
3181-
!fp->attrib_only && !stream_name) {
3182-
smb_break_all_oplock(work, fp);
3183-
need_truncate = 1;
3184-
}
31853180

31863181
/* fp should be searchable through ksmbd_inode.m_fp_list
31873182
* after daccess, saccess, attrib_only, and stream are
@@ -3197,13 +3192,39 @@ int smb2_open(struct ksmbd_work *work)
31973192
goto err_out;
31983193
}
31993194

3195+
rc = ksmbd_vfs_getattr(&path, &stat);
3196+
if (rc)
3197+
goto err_out;
3198+
3199+
if (stat.result_mask & STATX_BTIME)
3200+
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
3201+
else
3202+
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
3203+
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
3204+
fp->f_ci->m_fattr =
3205+
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
3206+
3207+
if (!created)
3208+
smb2_update_xattrs(tcon, &path, fp);
3209+
else
3210+
smb2_new_xattrs(tcon, &path, fp);
3211+
3212+
if (file_present || created)
3213+
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
3214+
3215+
if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
3216+
!fp->attrib_only && !stream_name) {
3217+
smb_break_all_oplock(work, fp);
3218+
need_truncate = 1;
3219+
}
3220+
32003221
share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
32013222
if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
32023223
(req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
32033224
!(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) {
32043225
if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) {
32053226
rc = share_ret;
3206-
goto err_out;
3227+
goto err_out1;
32073228
}
32083229
} else {
32093230
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
@@ -3213,7 +3234,7 @@ int smb2_open(struct ksmbd_work *work)
32133234
name, req_op_level, lc->req_state);
32143235
rc = find_same_lease_key(sess, fp->f_ci, lc);
32153236
if (rc)
3216-
goto err_out;
3237+
goto err_out1;
32173238
} else if (open_flags == O_RDONLY &&
32183239
(req_op_level == SMB2_OPLOCK_LEVEL_BATCH ||
32193240
req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))
@@ -3224,20 +3245,26 @@ int smb2_open(struct ksmbd_work *work)
32243245
le32_to_cpu(req->hdr.Id.SyncId.TreeId),
32253246
lc, share_ret);
32263247
if (rc < 0)
3227-
goto err_out;
3248+
goto err_out1;
32283249
}
32293250

32303251
if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
32313252
ksmbd_fd_set_delete_on_close(fp, file_info);
32323253

3254+
if (need_truncate) {
3255+
rc = smb2_create_truncate(&fp->filp->f_path);
3256+
if (rc)
3257+
goto err_out1;
3258+
}
3259+
32333260
if (req->CreateContextsOffset) {
32343261
struct create_alloc_size_req *az_req;
32353262

32363263
az_req = (struct create_alloc_size_req *)smb2_find_context_vals(req,
32373264
SMB2_CREATE_ALLOCATION_SIZE, 4);
32383265
if (IS_ERR(az_req)) {
32393266
rc = PTR_ERR(az_req);
3240-
goto err_out;
3267+
goto err_out1;
32413268
} else if (az_req) {
32423269
loff_t alloc_size;
32433270
int err;
@@ -3246,7 +3273,7 @@ int smb2_open(struct ksmbd_work *work)
32463273
le32_to_cpu(az_req->ccontext.DataLength) <
32473274
sizeof(struct create_alloc_size_req)) {
32483275
rc = -EINVAL;
3249-
goto err_out;
3276+
goto err_out1;
32503277
}
32513278
alloc_size = le64_to_cpu(az_req->AllocationSize);
32523279
ksmbd_debug(SMB,
@@ -3264,30 +3291,13 @@ int smb2_open(struct ksmbd_work *work)
32643291
context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4);
32653292
if (IS_ERR(context)) {
32663293
rc = PTR_ERR(context);
3267-
goto err_out;
3294+
goto err_out1;
32683295
} else if (context) {
32693296
ksmbd_debug(SMB, "get query on disk id context\n");
32703297
query_disk_id = 1;
32713298
}
32723299
}
32733300

3274-
rc = ksmbd_vfs_getattr(&path, &stat);
3275-
if (rc)
3276-
goto err_out;
3277-
3278-
if (stat.result_mask & STATX_BTIME)
3279-
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
3280-
else
3281-
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
3282-
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
3283-
fp->f_ci->m_fattr =
3284-
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
3285-
3286-
if (!created)
3287-
smb2_update_xattrs(tcon, &path, fp);
3288-
else
3289-
smb2_new_xattrs(tcon, &path, fp);
3290-
32913301
memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
32923302

32933303
rsp->StructureSize = cpu_to_le16(89);
@@ -3394,14 +3404,13 @@ int smb2_open(struct ksmbd_work *work)
33943404
}
33953405

33963406
err_out:
3397-
if (file_present || created)
3407+
if (rc && (file_present || created))
33983408
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
33993409

3400-
if (fp && need_truncate)
3401-
rc = smb2_create_truncate(&fp->filp->f_path);
3402-
3403-
ksmbd_revert_fsids(work);
34043410
err_out1:
3411+
ksmbd_revert_fsids(work);
3412+
3413+
err_out2:
34053414
if (!rc) {
34063415
ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
34073416
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);

0 commit comments

Comments
 (0)