Commit df60cee2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.7-rc3-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Memory leak fix

 - Fix possible deadlock in open

 - Multiple SMB3 leasing (caching) fixes including:
     - incorrect open count (found via xfstest generic/002 with leases)
     - lease breaking incorrect serialization
     - lease break error handling fix
     - fix sending async response when lease pending

 - Async command fix

* tag '6.7-rc3-smb3-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: don't update ->op_state as OPLOCK_STATE_NONE on error
  ksmbd: move setting SMB2_FLAGS_ASYNC_COMMAND and AsyncId
  ksmbd: release interim response after sending status pending response
  ksmbd: move oplock handling after unlock parent dir
  ksmbd: separately allocate ci per dentry
  ksmbd: fix possible deadlock in smb2_open
  ksmbd: prevent memory leak on error return
parents d095b18f cd80ce7e
...@@ -56,6 +56,9 @@ void ksmbd_free_work_struct(struct ksmbd_work *work) ...@@ -56,6 +56,9 @@ void ksmbd_free_work_struct(struct ksmbd_work *work)
kfree(work->tr_buf); kfree(work->tr_buf);
kvfree(work->request_buf); kvfree(work->request_buf);
kfree(work->iov); kfree(work->iov);
if (!list_empty(&work->interim_entry))
list_del(&work->interim_entry);
if (work->async_id) if (work->async_id)
ksmbd_release_id(&work->conn->async_ida, work->async_id); ksmbd_release_id(&work->conn->async_ida, work->async_id);
kmem_cache_free(work_cache, work); kmem_cache_free(work_cache, work);
...@@ -106,7 +109,7 @@ static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib, ...@@ -106,7 +109,7 @@ static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
void *aux_buf, unsigned int aux_size) void *aux_buf, unsigned int aux_size)
{ {
struct aux_read *ar; struct aux_read *ar = NULL;
int need_iov_cnt = 1; int need_iov_cnt = 1;
if (aux_size) { if (aux_size) {
...@@ -123,8 +126,11 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, ...@@ -123,8 +126,11 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
new = krealloc(work->iov, new = krealloc(work->iov,
sizeof(struct kvec) * work->iov_alloc_cnt, sizeof(struct kvec) * work->iov_alloc_cnt,
GFP_KERNEL | __GFP_ZERO); GFP_KERNEL | __GFP_ZERO);
if (!new) if (!new) {
kfree(ar);
work->iov_alloc_cnt -= 4;
return -ENOMEM; return -ENOMEM;
}
work->iov = new; work->iov = new;
} }
......
...@@ -833,7 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo) ...@@ -833,7 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
interim_entry); interim_entry);
setup_async_work(in_work, NULL, NULL); setup_async_work(in_work, NULL, NULL);
smb2_send_interim_resp(in_work, STATUS_PENDING); smb2_send_interim_resp(in_work, STATUS_PENDING);
list_del(&in_work->interim_entry); list_del_init(&in_work->interim_entry);
release_async_work(in_work);
} }
INIT_WORK(&work->work, __smb2_lease_break_noti); INIT_WORK(&work->work, __smb2_lease_break_noti);
ksmbd_queue_work(work); ksmbd_queue_work(work);
......
...@@ -657,13 +657,9 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls) ...@@ -657,13 +657,9 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls)
int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
{ {
struct smb2_hdr *rsp_hdr;
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
int id; int id;
rsp_hdr = ksmbd_resp_buf_next(work);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
id = ksmbd_acquire_async_msg_id(&conn->async_ida); id = ksmbd_acquire_async_msg_id(&conn->async_ida);
if (id < 0) { if (id < 0) {
pr_err("Failed to alloc async message id\n"); pr_err("Failed to alloc async message id\n");
...@@ -671,7 +667,6 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) ...@@ -671,7 +667,6 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
} }
work->asynchronous = true; work->asynchronous = true;
work->async_id = id; work->async_id = id;
rsp_hdr->Id.AsyncId = cpu_to_le64(id);
ksmbd_debug(SMB, ksmbd_debug(SMB,
"Send interim Response to inform async request id : %d\n", "Send interim Response to inform async request id : %d\n",
...@@ -723,6 +718,8 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status) ...@@ -723,6 +718,8 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
__SMB2_HEADER_STRUCTURE_SIZE); __SMB2_HEADER_STRUCTURE_SIZE);
rsp_hdr = smb2_get_msg(in_work->response_buf); rsp_hdr = smb2_get_msg(in_work->response_buf);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);
smb2_set_err_rsp(in_work); smb2_set_err_rsp(in_work);
rsp_hdr->Status = status; rsp_hdr->Status = status;
...@@ -2380,7 +2377,8 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, ...@@ -2380,7 +2377,8 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
rc = 0; rc = 0;
} else { } else {
rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value, rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value,
le16_to_cpu(eabuf->EaValueLength), 0); le16_to_cpu(eabuf->EaValueLength),
0, true);
if (rc < 0) { if (rc < 0) {
ksmbd_debug(SMB, ksmbd_debug(SMB,
"ksmbd_vfs_setxattr is failed(%d)\n", "ksmbd_vfs_setxattr is failed(%d)\n",
...@@ -2443,7 +2441,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path, ...@@ -2443,7 +2441,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
return -EBADF; return -EBADF;
} }
rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0); rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0, false);
if (rc < 0) if (rc < 0)
pr_err("Failed to store XATTR stream name :%d\n", rc); pr_err("Failed to store XATTR stream name :%d\n", rc);
return 0; return 0;
...@@ -2518,7 +2516,7 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path * ...@@ -2518,7 +2516,7 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *
da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
XATTR_DOSINFO_ITIME; XATTR_DOSINFO_ITIME;
rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da); rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da, false);
if (rc) if (rc)
ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
} }
...@@ -2608,7 +2606,7 @@ static int smb2_create_sd_buffer(struct ksmbd_work *work, ...@@ -2608,7 +2606,7 @@ static int smb2_create_sd_buffer(struct ksmbd_work *work,
sizeof(struct create_sd_buf_req)) sizeof(struct create_sd_buf_req))
return -EINVAL; return -EINVAL;
return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd, return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd,
le32_to_cpu(sd_buf->ccontext.DataLength), true); le32_to_cpu(sd_buf->ccontext.DataLength), true, false);
} }
static void ksmbd_acls_fattr(struct smb_fattr *fattr, static void ksmbd_acls_fattr(struct smb_fattr *fattr,
...@@ -2690,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2690,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work)
*(char *)req->Buffer == '\\') { *(char *)req->Buffer == '\\') {
pr_err("not allow directory name included leading slash\n"); pr_err("not allow directory name included leading slash\n");
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} }
name = smb2_get_name(req->Buffer, name = smb2_get_name(req->Buffer,
...@@ -2701,7 +2699,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2701,7 +2699,7 @@ int smb2_open(struct ksmbd_work *work)
if (rc != -ENOMEM) if (rc != -ENOMEM)
rc = -ENOENT; rc = -ENOENT;
name = NULL; name = NULL;
goto err_out1; goto err_out2;
} }
ksmbd_debug(SMB, "converted name = %s\n", name); ksmbd_debug(SMB, "converted name = %s\n", name);
...@@ -2709,28 +2707,28 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2709,28 +2707,28 @@ int smb2_open(struct ksmbd_work *work)
if (!test_share_config_flag(work->tcon->share_conf, if (!test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_STREAMS)) { KSMBD_SHARE_FLAG_STREAMS)) {
rc = -EBADF; rc = -EBADF;
goto err_out1; goto err_out2;
} }
rc = parse_stream_name(name, &stream_name, &s_type); rc = parse_stream_name(name, &stream_name, &s_type);
if (rc < 0) if (rc < 0)
goto err_out1; goto err_out2;
} }
rc = ksmbd_validate_filename(name); rc = ksmbd_validate_filename(name);
if (rc < 0) if (rc < 0)
goto err_out1; goto err_out2;
if (ksmbd_share_veto_filename(share, name)) { if (ksmbd_share_veto_filename(share, name)) {
rc = -ENOENT; rc = -ENOENT;
ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n", ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n",
name); name);
goto err_out1; goto err_out2;
} }
} else { } else {
name = kstrdup("", GFP_KERNEL); name = kstrdup("", GFP_KERNEL);
if (!name) { if (!name) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_out1; goto err_out2;
} }
} }
...@@ -2743,14 +2741,14 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2743,14 +2741,14 @@ int smb2_open(struct ksmbd_work *work)
le32_to_cpu(req->ImpersonationLevel)); le32_to_cpu(req->ImpersonationLevel));
rc = -EIO; rc = -EIO;
rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL; rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL;
goto err_out1; goto err_out2;
} }
if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) { if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) {
pr_err("Invalid create options : 0x%x\n", pr_err("Invalid create options : 0x%x\n",
le32_to_cpu(req->CreateOptions)); le32_to_cpu(req->CreateOptions));
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} else { } else {
if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE &&
req->CreateOptions & FILE_RANDOM_ACCESS_LE) req->CreateOptions & FILE_RANDOM_ACCESS_LE)
...@@ -2760,13 +2758,13 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2760,13 +2758,13 @@ int smb2_open(struct ksmbd_work *work)
(FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION |
FILE_RESERVE_OPFILTER_LE)) { FILE_RESERVE_OPFILTER_LE)) {
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto err_out1; goto err_out2;
} }
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) { if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {
req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); req->CreateOptions = ~(FILE_NO_COMPRESSION_LE);
} }
...@@ -2778,21 +2776,21 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2778,21 +2776,21 @@ int smb2_open(struct ksmbd_work *work)
pr_err("Invalid create disposition : 0x%x\n", pr_err("Invalid create disposition : 0x%x\n",
le32_to_cpu(req->CreateDisposition)); le32_to_cpu(req->CreateDisposition));
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} }
if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) { if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) {
pr_err("Invalid desired access : 0x%x\n", pr_err("Invalid desired access : 0x%x\n",
le32_to_cpu(req->DesiredAccess)); le32_to_cpu(req->DesiredAccess));
rc = -EACCES; rc = -EACCES;
goto err_out1; goto err_out2;
} }
if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) { if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) {
pr_err("Invalid file attribute : 0x%x\n", pr_err("Invalid file attribute : 0x%x\n",
le32_to_cpu(req->FileAttributes)); le32_to_cpu(req->FileAttributes));
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} }
if (req->CreateContextsOffset) { if (req->CreateContextsOffset) {
...@@ -2800,19 +2798,19 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2800,19 +2798,19 @@ int smb2_open(struct ksmbd_work *work)
context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4); context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4);
if (IS_ERR(context)) { if (IS_ERR(context)) {
rc = PTR_ERR(context); rc = PTR_ERR(context);
goto err_out1; goto err_out2;
} else if (context) { } else if (context) {
ea_buf = (struct create_ea_buf_req *)context; ea_buf = (struct create_ea_buf_req *)context;
if (le16_to_cpu(context->DataOffset) + if (le16_to_cpu(context->DataOffset) +
le32_to_cpu(context->DataLength) < le32_to_cpu(context->DataLength) <
sizeof(struct create_ea_buf_req)) { sizeof(struct create_ea_buf_req)) {
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} }
if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) { if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) {
rsp->hdr.Status = STATUS_ACCESS_DENIED; rsp->hdr.Status = STATUS_ACCESS_DENIED;
rc = -EACCES; rc = -EACCES;
goto err_out1; goto err_out2;
} }
} }
...@@ -2820,7 +2818,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2820,7 +2818,7 @@ int smb2_open(struct ksmbd_work *work)
SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4); SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4);
if (IS_ERR(context)) { if (IS_ERR(context)) {
rc = PTR_ERR(context); rc = PTR_ERR(context);
goto err_out1; goto err_out2;
} else if (context) { } else if (context) {
ksmbd_debug(SMB, ksmbd_debug(SMB,
"get query maximal access context\n"); "get query maximal access context\n");
...@@ -2831,11 +2829,11 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2831,11 +2829,11 @@ int smb2_open(struct ksmbd_work *work)
SMB2_CREATE_TIMEWARP_REQUEST, 4); SMB2_CREATE_TIMEWARP_REQUEST, 4);
if (IS_ERR(context)) { if (IS_ERR(context)) {
rc = PTR_ERR(context); rc = PTR_ERR(context);
goto err_out1; goto err_out2;
} else if (context) { } else if (context) {
ksmbd_debug(SMB, "get timewarp context\n"); ksmbd_debug(SMB, "get timewarp context\n");
rc = -EBADF; rc = -EBADF;
goto err_out1; goto err_out2;
} }
if (tcon->posix_extensions) { if (tcon->posix_extensions) {
...@@ -2843,7 +2841,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2843,7 +2841,7 @@ int smb2_open(struct ksmbd_work *work)
SMB2_CREATE_TAG_POSIX, 16); SMB2_CREATE_TAG_POSIX, 16);
if (IS_ERR(context)) { if (IS_ERR(context)) {
rc = PTR_ERR(context); rc = PTR_ERR(context);
goto err_out1; goto err_out2;
} else if (context) { } else if (context) {
struct create_posix *posix = struct create_posix *posix =
(struct create_posix *)context; (struct create_posix *)context;
...@@ -2851,7 +2849,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2851,7 +2849,7 @@ int smb2_open(struct ksmbd_work *work)
le32_to_cpu(context->DataLength) < le32_to_cpu(context->DataLength) <
sizeof(struct create_posix) - 4) { sizeof(struct create_posix) - 4) {
rc = -EINVAL; rc = -EINVAL;
goto err_out1; goto err_out2;
} }
ksmbd_debug(SMB, "get posix context\n"); ksmbd_debug(SMB, "get posix context\n");
...@@ -2863,7 +2861,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2863,7 +2861,7 @@ int smb2_open(struct ksmbd_work *work)
if (ksmbd_override_fsids(work)) { if (ksmbd_override_fsids(work)) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_out1; goto err_out2;
} }
rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,
...@@ -3038,7 +3036,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3038,7 +3036,7 @@ int smb2_open(struct ksmbd_work *work)
} }
} }
rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent)); rc = ksmbd_query_inode_status(path.dentry->d_parent);
if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) { if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) {
rc = -EBUSY; rc = -EBUSY;
goto err_out; goto err_out;
...@@ -3152,7 +3150,8 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3152,7 +3150,8 @@ int smb2_open(struct ksmbd_work *work)
idmap, idmap,
&path, &path,
pntsd, pntsd,
pntsd_size); pntsd_size,
false);
kfree(pntsd); kfree(pntsd);
if (rc) if (rc)
pr_err("failed to store ntacl in xattr : %d\n", pr_err("failed to store ntacl in xattr : %d\n",
...@@ -3175,11 +3174,6 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3175,11 +3174,6 @@ int smb2_open(struct ksmbd_work *work)
fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE | fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE |
FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE)); FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE));
if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
!fp->attrib_only && !stream_name) {
smb_break_all_oplock(work, fp);
need_truncate = 1;
}
/* fp should be searchable through ksmbd_inode.m_fp_list /* fp should be searchable through ksmbd_inode.m_fp_list
* after daccess, saccess, attrib_only, and stream are * after daccess, saccess, attrib_only, and stream are
...@@ -3195,13 +3189,39 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3195,13 +3189,39 @@ int smb2_open(struct ksmbd_work *work)
goto err_out; goto err_out;
} }
rc = ksmbd_vfs_getattr(&path, &stat);
if (rc)
goto err_out;
if (stat.result_mask & STATX_BTIME)
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
else
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
fp->f_ci->m_fattr =
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
if (!created)
smb2_update_xattrs(tcon, &path, fp);
else
smb2_new_xattrs(tcon, &path, fp);
if (file_present || created)
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
!fp->attrib_only && !stream_name) {
smb_break_all_oplock(work, fp);
need_truncate = 1;
}
share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
(req_op_level == SMB2_OPLOCK_LEVEL_LEASE && (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
!(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) {
if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) {
rc = share_ret; rc = share_ret;
goto err_out; goto err_out1;
} }
} else { } else {
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) { if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
...@@ -3211,7 +3231,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3211,7 +3231,7 @@ int smb2_open(struct ksmbd_work *work)
name, req_op_level, lc->req_state); name, req_op_level, lc->req_state);
rc = find_same_lease_key(sess, fp->f_ci, lc); rc = find_same_lease_key(sess, fp->f_ci, lc);
if (rc) if (rc)
goto err_out; goto err_out1;
} else if (open_flags == O_RDONLY && } else if (open_flags == O_RDONLY &&
(req_op_level == SMB2_OPLOCK_LEVEL_BATCH || (req_op_level == SMB2_OPLOCK_LEVEL_BATCH ||
req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))
...@@ -3222,16 +3242,16 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3222,16 +3242,16 @@ int smb2_open(struct ksmbd_work *work)
le32_to_cpu(req->hdr.Id.SyncId.TreeId), le32_to_cpu(req->hdr.Id.SyncId.TreeId),
lc, share_ret); lc, share_ret);
if (rc < 0) if (rc < 0)
goto err_out; goto err_out1;
} }
if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
ksmbd_fd_set_delete_on_close(fp, file_info); ksmbd_fd_set_delete_on_close(fp, file_info);
if (need_truncate) { if (need_truncate) {
rc = smb2_create_truncate(&path); rc = smb2_create_truncate(&fp->filp->f_path);
if (rc) if (rc)
goto err_out; goto err_out1;
} }
if (req->CreateContextsOffset) { if (req->CreateContextsOffset) {
...@@ -3241,7 +3261,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3241,7 +3261,7 @@ int smb2_open(struct ksmbd_work *work)
SMB2_CREATE_ALLOCATION_SIZE, 4); SMB2_CREATE_ALLOCATION_SIZE, 4);
if (IS_ERR(az_req)) { if (IS_ERR(az_req)) {
rc = PTR_ERR(az_req); rc = PTR_ERR(az_req);
goto err_out; goto err_out1;
} else if (az_req) { } else if (az_req) {
loff_t alloc_size; loff_t alloc_size;
int err; int err;
...@@ -3250,7 +3270,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3250,7 +3270,7 @@ int smb2_open(struct ksmbd_work *work)
le32_to_cpu(az_req->ccontext.DataLength) < le32_to_cpu(az_req->ccontext.DataLength) <
sizeof(struct create_alloc_size_req)) { sizeof(struct create_alloc_size_req)) {
rc = -EINVAL; rc = -EINVAL;
goto err_out; goto err_out1;
} }
alloc_size = le64_to_cpu(az_req->AllocationSize); alloc_size = le64_to_cpu(az_req->AllocationSize);
ksmbd_debug(SMB, ksmbd_debug(SMB,
...@@ -3268,30 +3288,13 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3268,30 +3288,13 @@ int smb2_open(struct ksmbd_work *work)
context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4); context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4);
if (IS_ERR(context)) { if (IS_ERR(context)) {
rc = PTR_ERR(context); rc = PTR_ERR(context);
goto err_out; goto err_out1;
} else if (context) { } else if (context) {
ksmbd_debug(SMB, "get query on disk id context\n"); ksmbd_debug(SMB, "get query on disk id context\n");
query_disk_id = 1; query_disk_id = 1;
} }
} }
rc = ksmbd_vfs_getattr(&path, &stat);
if (rc)
goto err_out;
if (stat.result_mask & STATX_BTIME)
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
else
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
fp->f_ci->m_fattr =
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
if (!created)
smb2_update_xattrs(tcon, &path, fp);
else
smb2_new_xattrs(tcon, &path, fp);
memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
rsp->StructureSize = cpu_to_le16(89); rsp->StructureSize = cpu_to_le16(89);
...@@ -3398,13 +3401,13 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3398,13 +3401,13 @@ int smb2_open(struct ksmbd_work *work)
} }
err_out: err_out:
if (file_present || created) { if (rc && (file_present || created))
inode_unlock(d_inode(parent_path.dentry)); ksmbd_vfs_kern_path_unlock(&parent_path, &path);
path_put(&path);
path_put(&parent_path);
}
ksmbd_revert_fsids(work);
err_out1: err_out1:
ksmbd_revert_fsids(work);
err_out2:
if (!rc) { if (!rc) {
ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED); ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
...@@ -5537,7 +5540,7 @@ static int smb2_rename(struct ksmbd_work *work, ...@@ -5537,7 +5540,7 @@ static int smb2_rename(struct ksmbd_work *work,
rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp), rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),
&fp->filp->f_path, &fp->filp->f_path,
xattr_stream_name, xattr_stream_name,
NULL, 0, 0); NULL, 0, 0, true);
if (rc < 0) { if (rc < 0) {
pr_err("failed to store stream name in xattr: %d\n", pr_err("failed to store stream name in xattr: %d\n",
rc); rc);
...@@ -5630,11 +5633,9 @@ static int smb2_create_link(struct ksmbd_work *work, ...@@ -5630,11 +5633,9 @@ static int smb2_create_link(struct ksmbd_work *work,
if (rc) if (rc)
rc = -EINVAL; rc = -EINVAL;
out: out:
if (file_present) { if (file_present)
inode_unlock(d_inode(parent_path.dentry)); ksmbd_vfs_kern_path_unlock(&parent_path, &path);
path_put(&path);
path_put(&parent_path);
}
if (!IS_ERR(link_name)) if (!IS_ERR(link_name))
kfree(link_name); kfree(link_name);
kfree(pathname); kfree(pathname);
...@@ -5701,7 +5702,8 @@ static int set_file_basic_info(struct ksmbd_file *fp, ...@@ -5701,7 +5702,8 @@ static int set_file_basic_info(struct ksmbd_file *fp,
da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
XATTR_DOSINFO_ITIME; XATTR_DOSINFO_ITIME;
rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da); rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da,
true);
if (rc) if (rc)
ksmbd_debug(SMB, ksmbd_debug(SMB,
"failed to restore file attribute in EA\n"); "failed to restore file attribute in EA\n");
...@@ -6013,7 +6015,7 @@ static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info, ...@@ -6013,7 +6015,7 @@ static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info,
fp->saccess |= FILE_SHARE_DELETE_LE; fp->saccess |= FILE_SHARE_DELETE_LE;
return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd, return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd,
buf_len, false); buf_len, false, true);
} }
/** /**
...@@ -7582,7 +7584,8 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, ...@@ -7582,7 +7584,8 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,
da.attr = le32_to_cpu(fp->f_ci->m_fattr); da.attr = le32_to_cpu(fp->f_ci->m_fattr);
ret = ksmbd_vfs_set_dos_attrib_xattr(idmap, ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,
&fp->filp->f_path, &da); &fp->filp->f_path,
&da, true);
if (ret) if (ret)
fp->f_ci->m_fattr = old_fattr; fp->f_ci->m_fattr = old_fattr;
} }
...@@ -8231,7 +8234,6 @@ static void smb21_lease_break_ack(struct ksmbd_work *work) ...@@ -8231,7 +8234,6 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
return; return;
err_out: err_out:
opinfo->op_state = OPLOCK_STATE_NONE;
wake_up_interruptible_all(&opinfo->oplock_q); wake_up_interruptible_all(&opinfo->oplock_q);
atomic_dec(&opinfo->breaking_cnt); atomic_dec(&opinfo->breaking_cnt);
wake_up_interruptible_all(&opinfo->oplock_brk); wake_up_interruptible_all(&opinfo->oplock_brk);
......
...@@ -1185,7 +1185,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, ...@@ -1185,7 +1185,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
pntsd_size += sizeof(struct smb_acl) + nt_size; pntsd_size += sizeof(struct smb_acl) + nt_size;
} }
ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size); ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size, false);
kfree(pntsd); kfree(pntsd);
} }
...@@ -1377,7 +1377,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ...@@ -1377,7 +1377,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
bool type_check) bool type_check, bool get_write)
{ {
int rc; int rc;
struct smb_fattr fattr = {{0}}; struct smb_fattr fattr = {{0}};
...@@ -1437,7 +1437,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, ...@@ -1437,7 +1437,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) {
/* Update WinACL in xattr */ /* Update WinACL in xattr */
ksmbd_vfs_remove_sd_xattrs(idmap, path); ksmbd_vfs_remove_sd_xattrs(idmap, path);
ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len); ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len,
get_write);
} }
out: out:
......
...@@ -207,7 +207,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ...@@ -207,7 +207,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
__le32 *pdaccess, int uid); __le32 *pdaccess, int uid);
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
bool type_check); bool type_check, bool get_write);
void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid);
void ksmbd_init_domain(u32 *sub_auth); void ksmbd_init_domain(u32 *sub_auth);
......
...@@ -97,6 +97,13 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, ...@@ -97,6 +97,13 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
return -ENOENT; return -ENOENT;
} }
err = mnt_want_write(parent_path->mnt);
if (err) {
path_put(parent_path);
putname(filename);
return -ENOENT;
}
inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT); inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT);
d = lookup_one_qstr_excl(&last, parent_path->dentry, 0); d = lookup_one_qstr_excl(&last, parent_path->dentry, 0);
if (IS_ERR(d)) if (IS_ERR(d))
...@@ -123,6 +130,7 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, ...@@ -123,6 +130,7 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
err_out: err_out:
inode_unlock(d_inode(parent_path->dentry)); inode_unlock(d_inode(parent_path->dentry));
mnt_drop_write(parent_path->mnt);
path_put(parent_path); path_put(parent_path);
putname(filename); putname(filename);
return -ENOENT; return -ENOENT;
...@@ -451,7 +459,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, ...@@ -451,7 +459,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
fp->stream.name, fp->stream.name,
(void *)stream_buf, (void *)stream_buf,
size, size,
0); 0,
true);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -593,10 +602,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path) ...@@ -593,10 +602,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
goto out_err; goto out_err;
} }
err = mnt_want_write(path->mnt);
if (err)
goto out_err;
idmap = mnt_idmap(path->mnt); idmap = mnt_idmap(path->mnt);
if (S_ISDIR(d_inode(path->dentry)->i_mode)) { if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
err = vfs_rmdir(idmap, d_inode(parent), path->dentry); err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
...@@ -607,7 +612,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path) ...@@ -607,7 +612,6 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
if (err) if (err)
ksmbd_debug(VFS, "unlink failed, err %d\n", err); ksmbd_debug(VFS, "unlink failed, err %d\n", err);
} }
mnt_drop_write(path->mnt);
out_err: out_err:
ksmbd_revert_fsids(work); ksmbd_revert_fsids(work);
...@@ -715,7 +719,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, ...@@ -715,7 +719,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
goto out3; goto out3;
} }
parent_fp = ksmbd_lookup_fd_inode(d_inode(old_child->d_parent)); parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
if (parent_fp) { if (parent_fp) {
if (parent_fp->daccess & FILE_DELETE_LE) { if (parent_fp->daccess & FILE_DELETE_LE) {
pr_err("parent dir is opened with delete access\n"); pr_err("parent dir is opened with delete access\n");
...@@ -907,18 +911,22 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap, ...@@ -907,18 +911,22 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
* @attr_value: xattr value to set * @attr_value: xattr value to set
* @attr_size: size of xattr value * @attr_size: size of xattr value
* @flags: destination buffer length * @flags: destination buffer length
* @get_write: get write access to a mount
* *
* Return: 0 on success, otherwise error * Return: 0 on success, otherwise error
*/ */
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap, int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
const struct path *path, const char *attr_name, const struct path *path, const char *attr_name,
void *attr_value, size_t attr_size, int flags) void *attr_value, size_t attr_size, int flags,
bool get_write)
{ {
int err; int err;
if (get_write == true) {
err = mnt_want_write(path->mnt); err = mnt_want_write(path->mnt);
if (err) if (err)
return err; return err;
}
err = vfs_setxattr(idmap, err = vfs_setxattr(idmap,
path->dentry, path->dentry,
...@@ -928,6 +936,7 @@ int ksmbd_vfs_setxattr(struct mnt_idmap *idmap, ...@@ -928,6 +936,7 @@ int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
flags); flags);
if (err) if (err)
ksmbd_debug(VFS, "setxattr failed, err %d\n", err); ksmbd_debug(VFS, "setxattr failed, err %d\n", err);
if (get_write == true)
mnt_drop_write(path->mnt); mnt_drop_write(path->mnt);
return err; return err;
} }
...@@ -1252,6 +1261,13 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, ...@@ -1252,6 +1261,13 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
} }
if (!err) { if (!err) {
err = mnt_want_write(parent_path->mnt);
if (err) {
path_put(path);
path_put(parent_path);
return err;
}
err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry); err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry);
if (err) { if (err) {
path_put(path); path_put(path);
...@@ -1261,6 +1277,14 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, ...@@ -1261,6 +1277,14 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
return err; return err;
} }
void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path)
{
inode_unlock(d_inode(parent_path->dentry));
mnt_drop_write(parent_path->mnt);
path_put(path);
path_put(parent_path);
}
struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
const char *name, const char *name,
unsigned int flags, unsigned int flags,
...@@ -1415,7 +1439,8 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id ...@@ -1415,7 +1439,8 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id
int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
const struct path *path, const struct path *path,
struct smb_ntsd *pntsd, int len) struct smb_ntsd *pntsd, int len,
bool get_write)
{ {
int rc; int rc;
struct ndr sd_ndr = {0}, acl_ndr = {0}; struct ndr sd_ndr = {0}, acl_ndr = {0};
...@@ -1475,7 +1500,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, ...@@ -1475,7 +1500,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
rc = ksmbd_vfs_setxattr(idmap, path, rc = ksmbd_vfs_setxattr(idmap, path,
XATTR_NAME_SD, sd_ndr.data, XATTR_NAME_SD, sd_ndr.data,
sd_ndr.offset, 0); sd_ndr.offset, 0, get_write);
if (rc < 0) if (rc < 0)
pr_err("Failed to store XATTR ntacl :%d\n", rc); pr_err("Failed to store XATTR ntacl :%d\n", rc);
...@@ -1564,7 +1589,8 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, ...@@ -1564,7 +1589,8 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
const struct path *path, const struct path *path,
struct xattr_dos_attrib *da) struct xattr_dos_attrib *da,
bool get_write)
{ {
struct ndr n; struct ndr n;
int err; int err;
...@@ -1574,7 +1600,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, ...@@ -1574,7 +1600,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
return err; return err;
err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE, err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE,
(void *)n.data, n.offset, 0); (void *)n.data, n.offset, 0, get_write);
if (err) if (err)
ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); ksmbd_debug(SMB, "failed to store dos attribute in xattr\n");
kfree(n.data); kfree(n.data);
...@@ -1846,10 +1872,6 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap, ...@@ -1846,10 +1872,6 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
} }
posix_state_to_acl(&acl_state, acls->a_entries); posix_state_to_acl(&acl_state, acls->a_entries);
rc = mnt_want_write(path->mnt);
if (rc)
goto out_err;
rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls); rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0) if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
...@@ -1861,9 +1883,7 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap, ...@@ -1861,9 +1883,7 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc); rc);
} }
mnt_drop_write(path->mnt);
out_err:
free_acl_state(&acl_state); free_acl_state(&acl_state);
posix_acl_release(acls); posix_acl_release(acls);
return rc; return rc;
...@@ -1893,10 +1913,6 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, ...@@ -1893,10 +1913,6 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
} }
} }
rc = mnt_want_write(path->mnt);
if (rc)
goto out_err;
rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls); rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0) if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
...@@ -1908,9 +1924,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, ...@@ -1908,9 +1924,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc); rc);
} }
mnt_drop_write(path->mnt);
out_err:
posix_acl_release(acls); posix_acl_release(acls);
return rc; return rc;
} }
...@@ -109,7 +109,8 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap, ...@@ -109,7 +109,8 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
int attr_name_len); int attr_name_len);
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap, int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
const struct path *path, const char *attr_name, const struct path *path, const char *attr_name,
void *attr_value, size_t attr_size, int flags); void *attr_value, size_t attr_size, int flags,
bool get_write);
int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
size_t *xattr_stream_name_size, int s_type); size_t *xattr_stream_name_size, int s_type);
int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
...@@ -117,6 +118,7 @@ int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap, ...@@ -117,6 +118,7 @@ int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
unsigned int flags, struct path *parent_path, unsigned int flags, struct path *parent_path,
struct path *path, bool caseless); struct path *path, bool caseless);
void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path);
struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
const char *name, const char *name,
unsigned int flags, unsigned int flags,
...@@ -144,14 +146,16 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path) ...@@ -144,14 +146,16 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path)
int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
const struct path *path, const struct path *path,
struct smb_ntsd *pntsd, int len); struct smb_ntsd *pntsd, int len,
bool get_write);
int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
struct dentry *dentry, struct dentry *dentry,
struct smb_ntsd **pntsd); struct smb_ntsd **pntsd);
int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
const struct path *path, const struct path *path,
struct xattr_dos_attrib *da); struct xattr_dos_attrib *da,
bool get_write);
int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct dentry *dentry,
struct xattr_dos_attrib *da); struct xattr_dos_attrib *da);
......
...@@ -66,14 +66,14 @@ static unsigned long inode_hash(struct super_block *sb, unsigned long hashval) ...@@ -66,14 +66,14 @@ static unsigned long inode_hash(struct super_block *sb, unsigned long hashval)
return tmp & inode_hash_mask; return tmp & inode_hash_mask;
} }
static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode) static struct ksmbd_inode *__ksmbd_inode_lookup(struct dentry *de)
{ {
struct hlist_head *head = inode_hashtable + struct hlist_head *head = inode_hashtable +
inode_hash(inode->i_sb, inode->i_ino); inode_hash(d_inode(de)->i_sb, (unsigned long)de);
struct ksmbd_inode *ci = NULL, *ret_ci = NULL; struct ksmbd_inode *ci = NULL, *ret_ci = NULL;
hlist_for_each_entry(ci, head, m_hash) { hlist_for_each_entry(ci, head, m_hash) {
if (ci->m_inode == inode) { if (ci->m_de == de) {
if (atomic_inc_not_zero(&ci->m_count)) if (atomic_inc_not_zero(&ci->m_count))
ret_ci = ci; ret_ci = ci;
break; break;
...@@ -84,26 +84,16 @@ static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode) ...@@ -84,26 +84,16 @@ static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp) static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp)
{ {
return __ksmbd_inode_lookup(file_inode(fp->filp)); return __ksmbd_inode_lookup(fp->filp->f_path.dentry);
} }
static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode) int ksmbd_query_inode_status(struct dentry *dentry)
{
struct ksmbd_inode *ci;
read_lock(&inode_hash_lock);
ci = __ksmbd_inode_lookup(inode);
read_unlock(&inode_hash_lock);
return ci;
}
int ksmbd_query_inode_status(struct inode *inode)
{ {
struct ksmbd_inode *ci; struct ksmbd_inode *ci;
int ret = KSMBD_INODE_STATUS_UNKNOWN; int ret = KSMBD_INODE_STATUS_UNKNOWN;
read_lock(&inode_hash_lock); read_lock(&inode_hash_lock);
ci = __ksmbd_inode_lookup(inode); ci = __ksmbd_inode_lookup(dentry);
if (ci) { if (ci) {
ret = KSMBD_INODE_STATUS_OK; ret = KSMBD_INODE_STATUS_OK;
if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
...@@ -143,7 +133,7 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, ...@@ -143,7 +133,7 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
static void ksmbd_inode_hash(struct ksmbd_inode *ci) static void ksmbd_inode_hash(struct ksmbd_inode *ci)
{ {
struct hlist_head *b = inode_hashtable + struct hlist_head *b = inode_hashtable +
inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino); inode_hash(d_inode(ci->m_de)->i_sb, (unsigned long)ci->m_de);
hlist_add_head(&ci->m_hash, b); hlist_add_head(&ci->m_hash, b);
} }
...@@ -157,7 +147,6 @@ static void ksmbd_inode_unhash(struct ksmbd_inode *ci) ...@@ -157,7 +147,6 @@ static void ksmbd_inode_unhash(struct ksmbd_inode *ci)
static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
{ {
ci->m_inode = file_inode(fp->filp);
atomic_set(&ci->m_count, 1); atomic_set(&ci->m_count, 1);
atomic_set(&ci->op_count, 0); atomic_set(&ci->op_count, 0);
atomic_set(&ci->sop_count, 0); atomic_set(&ci->sop_count, 0);
...@@ -166,6 +155,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) ...@@ -166,6 +155,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
INIT_LIST_HEAD(&ci->m_fp_list); INIT_LIST_HEAD(&ci->m_fp_list);
INIT_LIST_HEAD(&ci->m_op_list); INIT_LIST_HEAD(&ci->m_op_list);
rwlock_init(&ci->m_lock); rwlock_init(&ci->m_lock);
ci->m_de = fp->filp->f_path.dentry;
return 0; return 0;
} }
...@@ -488,12 +478,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid) ...@@ -488,12 +478,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
return fp; return fp;
} }
struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode) struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
{ {
struct ksmbd_file *lfp; struct ksmbd_file *lfp;
struct ksmbd_inode *ci; struct ksmbd_inode *ci;
struct inode *inode = d_inode(dentry);
ci = ksmbd_inode_lookup_by_vfsinode(inode); read_lock(&inode_hash_lock);
ci = __ksmbd_inode_lookup(dentry);
read_unlock(&inode_hash_lock);
if (!ci) if (!ci)
return NULL; return NULL;
......
...@@ -51,7 +51,7 @@ struct ksmbd_inode { ...@@ -51,7 +51,7 @@ struct ksmbd_inode {
atomic_t op_count; atomic_t op_count;
/* opinfo count for streams */ /* opinfo count for streams */
atomic_t sop_count; atomic_t sop_count;
struct inode *m_inode; struct dentry *m_de;
unsigned int m_flags; unsigned int m_flags;
struct hlist_node m_hash; struct hlist_node m_hash;
struct list_head m_fp_list; struct list_head m_fp_list;
...@@ -140,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id, ...@@ -140,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp); void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id); struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode); struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp); struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work); void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
...@@ -164,7 +164,7 @@ enum KSMBD_INODE_STATUS { ...@@ -164,7 +164,7 @@ enum KSMBD_INODE_STATUS {
KSMBD_INODE_STATUS_PENDING_DELETE, KSMBD_INODE_STATUS_PENDING_DELETE,
}; };
int ksmbd_query_inode_status(struct inode *inode); int ksmbd_query_inode_status(struct dentry *dentry);
bool ksmbd_inode_pending_delete(struct ksmbd_file *fp); bool ksmbd_inode_pending_delete(struct ksmbd_file *fp);
void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment