commit
7c4ed5ded8
@ -19,8 +19,8 @@ static DEFINE_MUTEX(init_lock);
|
||||
|
||||
static struct ksmbd_conn_ops default_conn_ops;
|
||||
|
||||
static LIST_HEAD(conn_list);
|
||||
static DEFINE_RWLOCK(conn_list_lock);
|
||||
LIST_HEAD(conn_list);
|
||||
DEFINE_RWLOCK(conn_list_lock);
|
||||
|
||||
/**
|
||||
* ksmbd_conn_free() - free resources of the connection instance
|
||||
@ -70,6 +70,9 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||
spin_lock_init(&conn->credits_lock);
|
||||
ida_init(&conn->async_ida);
|
||||
|
||||
spin_lock_init(&conn->llist_lock);
|
||||
INIT_LIST_HEAD(&conn->lock_list);
|
||||
|
||||
write_lock(&conn_list_lock);
|
||||
list_add(&conn->conns_list, &conn_list);
|
||||
write_unlock(&conn_list_lock);
|
||||
@ -120,7 +123,8 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
|
||||
list_empty(&work->async_request_entry))
|
||||
return 0;
|
||||
|
||||
atomic_dec(&conn->req_running);
|
||||
if (!work->multiRsp)
|
||||
atomic_dec(&conn->req_running);
|
||||
spin_lock(&conn->request_lock);
|
||||
if (!work->multiRsp) {
|
||||
list_del_init(&work->request_entry);
|
||||
|
@ -79,6 +79,9 @@ struct ksmbd_conn {
|
||||
char *ntlmssp_cryptkey;
|
||||
};
|
||||
|
||||
spinlock_t llist_lock;
|
||||
struct list_head lock_list;
|
||||
|
||||
struct preauth_integrity_info *preauth_info;
|
||||
|
||||
bool need_neg;
|
||||
@ -138,6 +141,9 @@ struct ksmbd_transport {
|
||||
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
|
||||
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
|
||||
|
||||
extern struct list_head conn_list;
|
||||
extern rwlock_t conn_list_lock;
|
||||
|
||||
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
|
||||
struct ksmbd_conn *ksmbd_conn_alloc(void);
|
||||
|
@ -43,9 +43,9 @@ struct ksmbd_work {
|
||||
* Current Local FID assigned compound response if SMB2 CREATE
|
||||
* command is present in compound request
|
||||
*/
|
||||
unsigned int compound_fid;
|
||||
unsigned int compound_pfid;
|
||||
unsigned int compound_sid;
|
||||
u64 compound_fid;
|
||||
u64 compound_pfid;
|
||||
u64 compound_sid;
|
||||
|
||||
const struct cred *saved_cred;
|
||||
|
||||
|
@ -1472,7 +1472,7 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag)
|
||||
next = le32_to_cpu(cc->Next);
|
||||
} while (next != 0);
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2131,7 +2131,7 @@ static inline int check_context_err(void *ctx, char *str)
|
||||
int err;
|
||||
|
||||
err = PTR_ERR(ctx);
|
||||
ksmbd_debug(SMB, "find context %s err %d\n", str, err);
|
||||
ksmbd_debug(SMB, "find context %s err %d\n", str, err ? err : -ENOENT);
|
||||
|
||||
if (err == -EINVAL) {
|
||||
pr_err("bad name length\n");
|
||||
@ -2319,25 +2319,23 @@ static int smb2_create_sd_buffer(struct ksmbd_work *work,
|
||||
struct path *path)
|
||||
{
|
||||
struct create_context *context;
|
||||
int rc = -ENOENT;
|
||||
struct create_sd_buf_req *sd_buf;
|
||||
|
||||
if (!req->CreateContextsOffset)
|
||||
return rc;
|
||||
return -ENOENT;
|
||||
|
||||
/* Parse SD BUFFER create contexts */
|
||||
context = smb2_find_context_vals(req, SMB2_CREATE_SD_BUFFER);
|
||||
if (context && !IS_ERR(context)) {
|
||||
struct create_sd_buf_req *sd_buf;
|
||||
if (!context)
|
||||
return -ENOENT;
|
||||
else if (IS_ERR(context))
|
||||
return PTR_ERR(context);
|
||||
|
||||
ksmbd_debug(SMB,
|
||||
"Set ACLs using SMB2_CREATE_SD_BUFFER context\n");
|
||||
sd_buf = (struct create_sd_buf_req *)context;
|
||||
rc = set_info_sec(work->conn, work->tcon,
|
||||
path, &sd_buf->ntsd,
|
||||
le32_to_cpu(sd_buf->ccontext.DataLength), true);
|
||||
}
|
||||
|
||||
return rc;
|
||||
ksmbd_debug(SMB,
|
||||
"Set ACLs using SMB2_CREATE_SD_BUFFER context\n");
|
||||
sd_buf = (struct create_sd_buf_req *)context;
|
||||
return set_info_sec(work->conn, work->tcon, path, &sd_buf->ntsd,
|
||||
le32_to_cpu(sd_buf->ccontext.DataLength), true);
|
||||
}
|
||||
|
||||
static void ksmbd_acls_fattr(struct smb_fattr *fattr, struct inode *inode)
|
||||
@ -2525,7 +2523,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
if (req->CreateContextsOffset) {
|
||||
/* Parse non-durable handle create contexts */
|
||||
context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER);
|
||||
if (IS_ERR(context)) {
|
||||
if (IS_ERR_OR_NULL(context)) {
|
||||
rc = check_context_err(context, SMB2_CREATE_EA_BUFFER);
|
||||
if (rc < 0)
|
||||
goto err_out1;
|
||||
@ -2540,7 +2538,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
|
||||
context = smb2_find_context_vals(req,
|
||||
SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST);
|
||||
if (IS_ERR(context)) {
|
||||
if (IS_ERR_OR_NULL(context)) {
|
||||
rc = check_context_err(context,
|
||||
SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST);
|
||||
if (rc < 0)
|
||||
@ -2553,7 +2551,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
|
||||
context = smb2_find_context_vals(req,
|
||||
SMB2_CREATE_TIMEWARP_REQUEST);
|
||||
if (IS_ERR(context)) {
|
||||
if (IS_ERR_OR_NULL(context)) {
|
||||
rc = check_context_err(context,
|
||||
SMB2_CREATE_TIMEWARP_REQUEST);
|
||||
if (rc < 0)
|
||||
@ -2567,7 +2565,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
if (tcon->posix_extensions) {
|
||||
context = smb2_find_context_vals(req,
|
||||
SMB2_CREATE_TAG_POSIX);
|
||||
if (IS_ERR(context)) {
|
||||
if (IS_ERR_OR_NULL(context)) {
|
||||
rc = check_context_err(context,
|
||||
SMB2_CREATE_TAG_POSIX);
|
||||
if (rc < 0)
|
||||
@ -2809,7 +2807,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
|
||||
/* Get Persistent-ID */
|
||||
ksmbd_open_durable_fd(fp);
|
||||
if (!HAS_FILE_ID(fp->persistent_id)) {
|
||||
if (!has_file_id(fp->persistent_id)) {
|
||||
rc = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
@ -2970,7 +2968,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
|
||||
az_req = (struct create_alloc_size_req *)smb2_find_context_vals(req,
|
||||
SMB2_CREATE_ALLOCATION_SIZE);
|
||||
if (IS_ERR(az_req)) {
|
||||
if (IS_ERR_OR_NULL(az_req)) {
|
||||
rc = check_context_err(az_req,
|
||||
SMB2_CREATE_ALLOCATION_SIZE);
|
||||
if (rc < 0)
|
||||
@ -2992,7 +2990,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID);
|
||||
if (IS_ERR(context)) {
|
||||
if (IS_ERR_OR_NULL(context)) {
|
||||
rc = check_context_err(context, SMB2_CREATE_QUERY_ON_DISK_ID);
|
||||
if (rc < 0)
|
||||
goto err_out;
|
||||
@ -3291,7 +3289,7 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
||||
char *conv_name;
|
||||
int conv_len;
|
||||
void *kstat;
|
||||
int struct_sz;
|
||||
int struct_sz, rc = 0;
|
||||
|
||||
conv_name = ksmbd_convert_dir_info_name(d_info,
|
||||
conn->local_nls,
|
||||
@ -3301,8 +3299,8 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
||||
|
||||
/* Somehow the name has only terminating NULL bytes */
|
||||
if (conv_len < 0) {
|
||||
kfree(conv_name);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto free_conv_name;
|
||||
}
|
||||
|
||||
struct_sz = readdir_info_level_struct_sz(info_level);
|
||||
@ -3311,7 +3309,8 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
||||
|
||||
if (next_entry_offset > d_info->out_buf_len) {
|
||||
d_info->out_buf_len = 0;
|
||||
return -ENOSPC;
|
||||
rc = -ENOSPC;
|
||||
goto free_conv_name;
|
||||
}
|
||||
|
||||
kstat = d_info->wptr;
|
||||
@ -3453,14 +3452,15 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
||||
d_info->data_count += next_entry_offset;
|
||||
d_info->out_buf_len -= next_entry_offset;
|
||||
d_info->wptr += next_entry_offset;
|
||||
kfree(conv_name);
|
||||
|
||||
ksmbd_debug(SMB,
|
||||
"info_level : %d, buf_len :%d, next_offset : %d, data_count : %d\n",
|
||||
info_level, d_info->out_buf_len,
|
||||
next_entry_offset, d_info->data_count);
|
||||
|
||||
return 0;
|
||||
free_conv_name:
|
||||
kfree(conv_name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct smb2_query_dir_private {
|
||||
@ -4575,15 +4575,15 @@ static int smb2_get_info_file(struct ksmbd_work *work,
|
||||
}
|
||||
|
||||
if (work->next_smb2_rcv_hdr_off) {
|
||||
if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %u\n",
|
||||
if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
|
||||
work->compound_fid);
|
||||
id = work->compound_fid;
|
||||
pid = work->compound_pfid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HAS_FILE_ID(id)) {
|
||||
if (!has_file_id(id)) {
|
||||
id = le64_to_cpu(req->VolatileFileId);
|
||||
pid = le64_to_cpu(req->PersistentFileId);
|
||||
}
|
||||
@ -4947,15 +4947,15 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
|
||||
}
|
||||
|
||||
if (work->next_smb2_rcv_hdr_off) {
|
||||
if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %u\n",
|
||||
if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
|
||||
work->compound_fid);
|
||||
id = work->compound_fid;
|
||||
pid = work->compound_pfid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HAS_FILE_ID(id)) {
|
||||
if (!has_file_id(id)) {
|
||||
id = le64_to_cpu(req->VolatileFileId);
|
||||
pid = le64_to_cpu(req->PersistentFileId);
|
||||
}
|
||||
@ -5081,7 +5081,7 @@ static noinline int smb2_close_pipe(struct ksmbd_work *work)
|
||||
*/
|
||||
int smb2_close(struct ksmbd_work *work)
|
||||
{
|
||||
unsigned int volatile_id = KSMBD_NO_FID;
|
||||
u64 volatile_id = KSMBD_NO_FID;
|
||||
u64 sess_id;
|
||||
struct smb2_close_req *req;
|
||||
struct smb2_close_rsp *rsp;
|
||||
@ -5117,15 +5117,16 @@ int smb2_close(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
if (work->next_smb2_rcv_hdr_off &&
|
||||
!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) {
|
||||
if (!HAS_FILE_ID(work->compound_fid)) {
|
||||
!has_file_id(le64_to_cpu(req->VolatileFileId))) {
|
||||
if (!has_file_id(work->compound_fid)) {
|
||||
/* file already closed, return FILE_CLOSED */
|
||||
ksmbd_debug(SMB, "file already closed\n");
|
||||
rsp->hdr.Status = STATUS_FILE_CLOSED;
|
||||
err = -EBADF;
|
||||
goto out;
|
||||
} else {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %u:%u\n",
|
||||
ksmbd_debug(SMB,
|
||||
"Compound request set FID = %llu:%llu\n",
|
||||
work->compound_fid,
|
||||
work->compound_pfid);
|
||||
volatile_id = work->compound_fid;
|
||||
@ -5137,7 +5138,7 @@ int smb2_close(struct ksmbd_work *work)
|
||||
} else {
|
||||
volatile_id = le64_to_cpu(req->VolatileFileId);
|
||||
}
|
||||
ksmbd_debug(SMB, "volatile_id = %u\n", volatile_id);
|
||||
ksmbd_debug(SMB, "volatile_id = %llu\n", volatile_id);
|
||||
|
||||
rsp->StructureSize = cpu_to_le16(60);
|
||||
rsp->Reserved = 0;
|
||||
@ -5787,8 +5788,8 @@ int smb2_set_info(struct ksmbd_work *work)
|
||||
if (work->next_smb2_rcv_hdr_off) {
|
||||
req = ksmbd_req_buf_next(work);
|
||||
rsp = ksmbd_resp_buf_next(work);
|
||||
if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %u\n",
|
||||
if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
|
||||
work->compound_fid);
|
||||
id = work->compound_fid;
|
||||
pid = work->compound_pfid;
|
||||
@ -5798,7 +5799,7 @@ int smb2_set_info(struct ksmbd_work *work)
|
||||
rsp = work->response_buf;
|
||||
}
|
||||
|
||||
if (!HAS_FILE_ID(id)) {
|
||||
if (!has_file_id(id)) {
|
||||
id = le64_to_cpu(req->VolatileFileId);
|
||||
pid = le64_to_cpu(req->PersistentFileId);
|
||||
}
|
||||
@ -6510,8 +6511,9 @@ static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock,
|
||||
lock->flags = flags;
|
||||
if (lock->start == lock->end)
|
||||
lock->zero_len = 1;
|
||||
INIT_LIST_HEAD(&lock->clist);
|
||||
INIT_LIST_HEAD(&lock->flist);
|
||||
INIT_LIST_HEAD(&lock->llist);
|
||||
INIT_LIST_HEAD(&lock->glist);
|
||||
list_add_tail(&lock->llist, lock_list);
|
||||
|
||||
return lock;
|
||||
@ -6550,7 +6552,8 @@ int smb2_lock(struct ksmbd_work *work)
|
||||
int cmd = 0;
|
||||
int err = 0, i;
|
||||
u64 lock_start, lock_length;
|
||||
struct ksmbd_lock *smb_lock = NULL, *cmp_lock, *tmp;
|
||||
struct ksmbd_lock *smb_lock = NULL, *cmp_lock, *tmp, *tmp2;
|
||||
struct ksmbd_conn *conn;
|
||||
int nolock = 0;
|
||||
LIST_HEAD(lock_list);
|
||||
LIST_HEAD(rollback_list);
|
||||
@ -6659,72 +6662,89 @@ int smb2_lock(struct ksmbd_work *work)
|
||||
|
||||
if (!(smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) &&
|
||||
!(smb_lock->flags & SMB2_LOCKFLAG_FAIL_IMMEDIATELY))
|
||||
goto no_check_gl;
|
||||
goto no_check_cl;
|
||||
|
||||
nolock = 1;
|
||||
/* check locks in global list */
|
||||
list_for_each_entry(cmp_lock, &global_lock_list, glist) {
|
||||
if (file_inode(cmp_lock->fl->fl_file) !=
|
||||
file_inode(smb_lock->fl->fl_file))
|
||||
continue;
|
||||
/* check locks in connection list */
|
||||
read_lock(&conn_list_lock);
|
||||
list_for_each_entry(conn, &conn_list, conns_list) {
|
||||
spin_lock(&conn->llist_lock);
|
||||
list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
|
||||
if (file_inode(cmp_lock->fl->fl_file) !=
|
||||
file_inode(smb_lock->fl->fl_file))
|
||||
continue;
|
||||
|
||||
if (smb_lock->fl->fl_type == F_UNLCK) {
|
||||
if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file &&
|
||||
cmp_lock->start == smb_lock->start &&
|
||||
cmp_lock->end == smb_lock->end &&
|
||||
!lock_defer_pending(cmp_lock->fl)) {
|
||||
nolock = 0;
|
||||
locks_free_lock(cmp_lock->fl);
|
||||
list_del(&cmp_lock->glist);
|
||||
kfree(cmp_lock);
|
||||
break;
|
||||
if (smb_lock->fl->fl_type == F_UNLCK) {
|
||||
if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file &&
|
||||
cmp_lock->start == smb_lock->start &&
|
||||
cmp_lock->end == smb_lock->end &&
|
||||
!lock_defer_pending(cmp_lock->fl)) {
|
||||
nolock = 0;
|
||||
list_del(&cmp_lock->flist);
|
||||
list_del(&cmp_lock->clist);
|
||||
spin_unlock(&conn->llist_lock);
|
||||
read_unlock(&conn_list_lock);
|
||||
|
||||
locks_free_lock(cmp_lock->fl);
|
||||
kfree(cmp_lock);
|
||||
goto out_check_cl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file) {
|
||||
if (smb_lock->flags & SMB2_LOCKFLAG_SHARED)
|
||||
continue;
|
||||
} else {
|
||||
if (cmp_lock->flags & SMB2_LOCKFLAG_SHARED)
|
||||
continue;
|
||||
}
|
||||
if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file) {
|
||||
if (smb_lock->flags & SMB2_LOCKFLAG_SHARED)
|
||||
continue;
|
||||
} else {
|
||||
if (cmp_lock->flags & SMB2_LOCKFLAG_SHARED)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check zero byte lock range */
|
||||
if (cmp_lock->zero_len && !smb_lock->zero_len &&
|
||||
cmp_lock->start > smb_lock->start &&
|
||||
cmp_lock->start < smb_lock->end) {
|
||||
pr_err("previous lock conflict with zero byte lock range\n");
|
||||
rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;
|
||||
/* check zero byte lock range */
|
||||
if (cmp_lock->zero_len && !smb_lock->zero_len &&
|
||||
cmp_lock->start > smb_lock->start &&
|
||||
cmp_lock->start < smb_lock->end) {
|
||||
spin_unlock(&conn->llist_lock);
|
||||
read_unlock(&conn_list_lock);
|
||||
pr_err("previous lock conflict with zero byte lock range\n");
|
||||
rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (smb_lock->zero_len && !cmp_lock->zero_len &&
|
||||
smb_lock->start > cmp_lock->start &&
|
||||
smb_lock->start < cmp_lock->end) {
|
||||
spin_unlock(&conn->llist_lock);
|
||||
read_unlock(&conn_list_lock);
|
||||
pr_err("current lock conflict with zero byte lock range\n");
|
||||
rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (((cmp_lock->start <= smb_lock->start &&
|
||||
cmp_lock->end > smb_lock->start) ||
|
||||
(cmp_lock->start < smb_lock->end &&
|
||||
cmp_lock->end >= smb_lock->end)) &&
|
||||
!cmp_lock->zero_len && !smb_lock->zero_len) {
|
||||
spin_unlock(&conn->llist_lock);
|
||||
read_unlock(&conn_list_lock);
|
||||
pr_err("Not allow lock operation on exclusive lock range\n");
|
||||
rsp->hdr.Status =
|
||||
STATUS_LOCK_NOT_GRANTED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (smb_lock->zero_len && !cmp_lock->zero_len &&
|
||||
smb_lock->start > cmp_lock->start &&
|
||||
smb_lock->start < cmp_lock->end) {
|
||||
pr_err("current lock conflict with zero byte lock range\n");
|
||||
rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (((cmp_lock->start <= smb_lock->start &&
|
||||
cmp_lock->end > smb_lock->start) ||
|
||||
(cmp_lock->start < smb_lock->end && cmp_lock->end >= smb_lock->end)) &&
|
||||
!cmp_lock->zero_len && !smb_lock->zero_len) {
|
||||
pr_err("Not allow lock operation on exclusive lock range\n");
|
||||
rsp->hdr.Status =
|
||||
STATUS_LOCK_NOT_GRANTED;
|
||||
goto out;
|
||||
}
|
||||
spin_unlock(&conn->llist_lock);
|
||||
}
|
||||
|
||||
read_unlock(&conn_list_lock);
|
||||
out_check_cl:
|
||||
if (smb_lock->fl->fl_type == F_UNLCK && nolock) {
|
||||
pr_err("Try to unlock nolocked range\n");
|
||||
rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
no_check_gl:
|
||||
no_check_cl:
|
||||
if (smb_lock->zero_len) {
|
||||
err = 0;
|
||||
goto skip;
|
||||
@ -6750,8 +6770,10 @@ skip:
|
||||
|
||||
ksmbd_debug(SMB,
|
||||
"would have to wait for getting lock\n");
|
||||
list_add_tail(&smb_lock->glist,
|
||||
&global_lock_list);
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
list_add_tail(&smb_lock->clist,
|
||||
&work->conn->lock_list);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
list_add(&smb_lock->llist, &rollback_list);
|
||||
|
||||
argv = kmalloc(sizeof(void *), GFP_KERNEL);
|
||||
@ -6775,11 +6797,13 @@ skip:
|
||||
|
||||
smb2_send_interim_resp(work, STATUS_PENDING);
|
||||
|
||||
err = ksmbd_vfs_posix_lock_wait(flock);
|
||||
ksmbd_vfs_posix_lock_wait(flock);
|
||||
|
||||
if (work->state != KSMBD_WORK_ACTIVE) {
|
||||
list_del(&smb_lock->llist);
|
||||
list_del(&smb_lock->glist);
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
list_del(&smb_lock->clist);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
locks_free_lock(flock);
|
||||
|
||||
if (work->state == KSMBD_WORK_CANCELLED) {
|
||||
@ -6803,14 +6827,21 @@ skip:
|
||||
}
|
||||
|
||||
list_del(&smb_lock->llist);
|
||||
list_del(&smb_lock->glist);
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
list_del(&smb_lock->clist);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
|
||||
spin_lock(&fp->f_lock);
|
||||
list_del(&work->fp_entry);
|
||||
spin_unlock(&fp->f_lock);
|
||||
goto retry;
|
||||
} else if (!err) {
|
||||
list_add_tail(&smb_lock->glist,
|
||||
&global_lock_list);
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
list_add_tail(&smb_lock->clist,
|
||||
&work->conn->lock_list);
|
||||
list_add_tail(&smb_lock->flist,
|
||||
&fp->lock_list);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
list_add(&smb_lock->llist, &rollback_list);
|
||||
ksmbd_debug(SMB, "successful in taking lock\n");
|
||||
} else {
|
||||
@ -6849,8 +6880,14 @@ out:
|
||||
err = vfs_lock_file(filp, 0, rlock, NULL);
|
||||
if (err)
|
||||
pr_err("rollback unlock fail : %d\n", err);
|
||||
|
||||
list_del(&smb_lock->llist);
|
||||
list_del(&smb_lock->glist);
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
if (!list_empty(&smb_lock->flist))
|
||||
list_del(&smb_lock->flist);
|
||||
list_del(&smb_lock->clist);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
|
||||
locks_free_lock(smb_lock->fl);
|
||||
locks_free_lock(rlock);
|
||||
kfree(smb_lock);
|
||||
@ -7004,11 +7041,6 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,
|
||||
|
||||
rtnl_lock();
|
||||
for_each_netdev(&init_net, netdev) {
|
||||
if (unlikely(!netdev)) {
|
||||
rtnl_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (netdev->type == ARPHRD_LOOPBACK)
|
||||
continue;
|
||||
|
||||
@ -7290,8 +7322,8 @@ int smb2_ioctl(struct ksmbd_work *work)
|
||||
if (work->next_smb2_rcv_hdr_off) {
|
||||
req = ksmbd_req_buf_next(work);
|
||||
rsp = ksmbd_resp_buf_next(work);
|
||||
if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %u\n",
|
||||
if (!has_file_id(le64_to_cpu(req->VolatileFileId))) {
|
||||
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
|
||||
work->compound_fid);
|
||||
id = work->compound_fid;
|
||||
}
|
||||
@ -7300,7 +7332,7 @@ int smb2_ioctl(struct ksmbd_work *work)
|
||||
rsp = work->response_buf;
|
||||
}
|
||||
|
||||
if (!HAS_FILE_ID(id))
|
||||
if (!has_file_id(id))
|
||||
id = le64_to_cpu(req->VolatileFileId);
|
||||
|
||||
if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) {
|
||||
|
@ -23,8 +23,6 @@ static const char basechars[43] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
|
||||
#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
|
||||
#define KSMBD_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr))
|
||||
|
||||
LIST_HEAD(global_lock_list);
|
||||
|
||||
struct smb_protocol {
|
||||
int index;
|
||||
char *name;
|
||||
|
@ -48,8 +48,6 @@
|
||||
#define CIFS_DEFAULT_IOSIZE (64 * 1024)
|
||||
#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
|
||||
|
||||
extern struct list_head global_lock_list;
|
||||
|
||||
/* RFC 1002 session packet types */
|
||||
#define RFC1002_SESSION_MESSAGE 0x00
|
||||
#define RFC1002_SESSION_REQUEST 0x81
|
||||
|
@ -962,25 +962,29 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
struct dentry *parent = path->dentry->d_parent;
|
||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||
int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0;
|
||||
int rc = -ENOENT, num_aces, dacloffset, pntsd_type, acl_len;
|
||||
int rc = 0, num_aces, dacloffset, pntsd_type, acl_len;
|
||||
char *aces_base;
|
||||
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
|
||||
|
||||
acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns,
|
||||
parent, &parent_pntsd);
|
||||
if (acl_len <= 0)
|
||||
return rc;
|
||||
return -ENOENT;
|
||||
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
|
||||
if (!dacloffset)
|
||||
goto out;
|
||||
if (!dacloffset) {
|
||||
rc = -EINVAL;
|
||||
goto free_parent_pntsd;
|
||||
}
|
||||
|
||||
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
|
||||
num_aces = le32_to_cpu(parent_pdacl->num_aces);
|
||||
pntsd_type = le16_to_cpu(parent_pntsd->type);
|
||||
|
||||
aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
|
||||
if (!aces_base)
|
||||
goto out;
|
||||
if (!aces_base) {
|
||||
rc = -ENOMEM;
|
||||
goto free_parent_pntsd;
|
||||
}
|
||||
|
||||
aces = (struct smb_ace *)aces_base;
|
||||
parent_aces = (struct smb_ace *)((char *)parent_pdacl +
|
||||
@ -1060,7 +1064,7 @@ pass:
|
||||
nt_size, GFP_KERNEL);
|
||||
if (!pntsd) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
goto free_aces_base;
|
||||
}
|
||||
|
||||
pntsd->revision = cpu_to_le16(1);
|
||||
@ -1101,11 +1105,12 @@ pass:
|
||||
ksmbd_vfs_set_sd_xattr(conn, user_ns,
|
||||
path->dentry, pntsd, pntsd_size);
|
||||
kfree(pntsd);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
free_aces_base:
|
||||
kfree(aces_base);
|
||||
out:
|
||||
free_parent_pntsd:
|
||||
kfree(parent_pntsd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1207,10 +1207,8 @@ static int smb_direct_writev(struct ksmbd_transport *t,
|
||||
struct kvec vec;
|
||||
struct smb_direct_send_ctx send_ctx;
|
||||
|
||||
if (st->status != SMB_DIRECT_CS_CONNECTED) {
|
||||
ret = -ENOTCONN;
|
||||
goto done;
|
||||
}
|
||||
if (st->status != SMB_DIRECT_CS_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
//FIXME: skip RFC1002 header..
|
||||
buflen -= 4;
|
||||
|
@ -1698,35 +1698,20 @@ out:
|
||||
int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
|
||||
size_t *xattr_stream_name_size, int s_type)
|
||||
{
|
||||
int stream_name_size;
|
||||
char *xattr_stream_name_buf;
|
||||
char *type;
|
||||
int type_len;
|
||||
char *type, *buf;
|
||||
|
||||
if (s_type == DIR_STREAM)
|
||||
type = ":$INDEX_ALLOCATION";
|
||||
else
|
||||
type = ":$DATA";
|
||||
|
||||
type_len = strlen(type);
|
||||
stream_name_size = strlen(stream_name);
|
||||
*xattr_stream_name_size = stream_name_size + XATTR_NAME_STREAM_LEN + 1;
|
||||
xattr_stream_name_buf = kmalloc(*xattr_stream_name_size + type_len,
|
||||
GFP_KERNEL);
|
||||
if (!xattr_stream_name_buf)
|
||||
buf = kasprintf(GFP_KERNEL, "%s%s%s",
|
||||
XATTR_NAME_STREAM, stream_name, type);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(xattr_stream_name_buf, XATTR_NAME_STREAM, XATTR_NAME_STREAM_LEN);
|
||||
|
||||
if (stream_name_size) {
|
||||
memcpy(&xattr_stream_name_buf[XATTR_NAME_STREAM_LEN],
|
||||
stream_name, stream_name_size);
|
||||
}
|
||||
memcpy(&xattr_stream_name_buf[*xattr_stream_name_size - 1], type, type_len);
|
||||
*xattr_stream_name_size += type_len;
|
||||
|
||||
xattr_stream_name_buf[*xattr_stream_name_size - 1] = '\0';
|
||||
*xattr_stream_name = xattr_stream_name_buf;
|
||||
*xattr_stream_name = buf;
|
||||
*xattr_stream_name_size = strlen(buf) + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1799,9 +1784,9 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_vfs_posix_lock_wait(struct file_lock *flock)
|
||||
void ksmbd_vfs_posix_lock_wait(struct file_lock *flock)
|
||||
{
|
||||
return wait_event_interruptible(flock->fl_wait, !flock->fl_blocker);
|
||||
wait_event(flock->fl_wait, !flock->fl_blocker);
|
||||
}
|
||||
|
||||
int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout)
|
||||
|
@ -168,7 +168,7 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
|
||||
struct user_namespace *user_ns,
|
||||
struct dentry *dentry,
|
||||
struct ksmbd_kstat *ksmbd_kstat);
|
||||
int ksmbd_vfs_posix_lock_wait(struct file_lock *flock);
|
||||
void ksmbd_vfs_posix_lock_wait(struct file_lock *flock);
|
||||
int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout);
|
||||
void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock);
|
||||
int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns,
|
||||
|
@ -277,7 +277,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
|
||||
|
||||
static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
||||
{
|
||||
if (!HAS_FILE_ID(fp->persistent_id))
|
||||
if (!has_file_id(fp->persistent_id))
|
||||
return;
|
||||
|
||||
write_lock(&global_ft.lock);
|
||||
@ -287,7 +287,7 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
||||
|
||||
static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
{
|
||||
if (!HAS_FILE_ID(fp->volatile_id))
|
||||
if (!has_file_id(fp->volatile_id))
|
||||
return;
|
||||
|
||||
write_lock(&fp->f_ci->m_lock);
|
||||
@ -302,6 +302,7 @@ static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp
|
||||
static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
{
|
||||
struct file *filp;
|
||||
struct ksmbd_lock *smb_lock, *tmp_lock;
|
||||
|
||||
fd_limit_close();
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
@ -313,6 +314,20 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
__ksmbd_inode_close(fp);
|
||||
if (!IS_ERR_OR_NULL(filp))
|
||||
fput(filp);
|
||||
|
||||
/* because the reference count of fp is 0, it is guaranteed that
|
||||
* there are not accesses to fp->lock_list.
|
||||
*/
|
||||
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
|
||||
spin_lock(&fp->conn->llist_lock);
|
||||
list_del(&smb_lock->clist);
|
||||
spin_unlock(&fp->conn->llist_lock);
|
||||
|
||||
list_del(&smb_lock->flist);
|
||||
locks_free_lock(smb_lock->fl);
|
||||
kfree(smb_lock);
|
||||
}
|
||||
|
||||
kfree(fp->filename);
|
||||
if (ksmbd_stream_fd(fp))
|
||||
kfree(fp->stream.name);
|
||||
@ -327,10 +342,13 @@ static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
|
||||
}
|
||||
|
||||
static struct ksmbd_file *__ksmbd_lookup_fd(struct ksmbd_file_table *ft,
|
||||
unsigned int id)
|
||||
u64 id)
|
||||
{
|
||||
struct ksmbd_file *fp;
|
||||
|
||||
if (!has_file_id(id))
|
||||
return NULL;
|
||||
|
||||
read_lock(&ft->lock);
|
||||
fp = idr_find(ft->idr, id);
|
||||
if (fp)
|
||||
@ -359,12 +377,12 @@ static void set_close_state_blocked_works(struct ksmbd_file *fp)
|
||||
spin_unlock(&fp->f_lock);
|
||||
}
|
||||
|
||||
int ksmbd_close_fd(struct ksmbd_work *work, unsigned int id)
|
||||
int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
|
||||
{
|
||||
struct ksmbd_file *fp;
|
||||
struct ksmbd_file_table *ft;
|
||||
|
||||
if (!HAS_FILE_ID(id))
|
||||
if (!has_file_id(id))
|
||||
return 0;
|
||||
|
||||
ft = &work->sess->file_table;
|
||||
@ -404,12 +422,12 @@ static bool __sanity_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *f
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, unsigned int id)
|
||||
struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id)
|
||||
{
|
||||
return __ksmbd_lookup_fd(&work->sess->file_table, id);
|
||||
}
|
||||
|
||||
struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, unsigned int id)
|
||||
struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id)
|
||||
{
|
||||
struct ksmbd_file *fp = __ksmbd_lookup_fd(&work->sess->file_table, id);
|
||||
|
||||
@ -420,19 +438,16 @@ struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, unsigned int id
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, unsigned int id,
|
||||
unsigned int pid)
|
||||
struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
|
||||
u64 pid)
|
||||
{
|
||||
struct ksmbd_file *fp;
|
||||
|
||||
if (!HAS_FILE_ID(id)) {
|
||||
if (!has_file_id(id)) {
|
||||
id = work->compound_fid;
|
||||
pid = work->compound_pfid;
|
||||
}
|
||||
|
||||
if (!HAS_FILE_ID(id))
|
||||
return NULL;
|
||||
|
||||
fp = __ksmbd_lookup_fd(&work->sess->file_table, id);
|
||||
if (!__sanity_check(work->tcon, fp)) {
|
||||
ksmbd_fd_put(work, fp);
|
||||
@ -494,7 +509,7 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode)
|
||||
#define OPEN_ID_TYPE_VOLATILE_ID (0)
|
||||
#define OPEN_ID_TYPE_PERSISTENT_ID (1)
|
||||
|
||||
static void __open_id_set(struct ksmbd_file *fp, unsigned int id, int type)
|
||||
static void __open_id_set(struct ksmbd_file *fp, u64 id, int type)
|
||||
{
|
||||
if (type == OPEN_ID_TYPE_VOLATILE_ID)
|
||||
fp->volatile_id = id;
|
||||
@ -505,7 +520,7 @@ static void __open_id_set(struct ksmbd_file *fp, unsigned int id, int type)
|
||||
static int __open_id(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
int type)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
u64 id = 0;
|
||||
int ret;
|
||||
|
||||
if (type == OPEN_ID_TYPE_VOLATILE_ID && fd_limit_depleted()) {
|
||||
@ -515,7 +530,7 @@ static int __open_id(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
write_lock(&ft->lock);
|
||||
ret = idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX, GFP_NOWAIT);
|
||||
ret = idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX - 1, GFP_NOWAIT);
|
||||
if (ret >= 0) {
|
||||
id = ret;
|
||||
ret = 0;
|
||||
@ -549,6 +564,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
|
||||
|
||||
INIT_LIST_HEAD(&fp->blocked_works);
|
||||
INIT_LIST_HEAD(&fp->node);
|
||||
INIT_LIST_HEAD(&fp->lock_list);
|
||||
spin_lock_init(&fp->f_lock);
|
||||
atomic_set(&fp->refcount, 1);
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define FILE_GENERIC_EXECUTE 0X1200a0
|
||||
|
||||
#define KSMBD_START_FID 0
|
||||
#define KSMBD_NO_FID (UINT_MAX)
|
||||
#define KSMBD_NO_FID (INT_MAX)
|
||||
#define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL)
|
||||
|
||||
struct ksmbd_conn;
|
||||
@ -30,7 +30,8 @@ struct ksmbd_session;
|
||||
|
||||
struct ksmbd_lock {
|
||||
struct file_lock *fl;
|
||||
struct list_head glist;
|
||||
struct list_head clist;
|
||||
struct list_head flist;
|
||||
struct list_head llist;
|
||||
unsigned int flags;
|
||||
int cmd;
|
||||
@ -62,8 +63,8 @@ struct ksmbd_inode {
|
||||
struct ksmbd_file {
|
||||
struct file *filp;
|
||||
char *filename;
|
||||
unsigned int persistent_id;
|
||||
unsigned int volatile_id;
|
||||
u64 persistent_id;
|
||||
u64 volatile_id;
|
||||
|
||||
spinlock_t f_lock;
|
||||
|
||||
@ -91,6 +92,7 @@ struct ksmbd_file {
|
||||
struct stream stream;
|
||||
struct list_head node;
|
||||
struct list_head blocked_works;
|
||||
struct list_head lock_list;
|
||||
|
||||
int durable_timeout;
|
||||
|
||||
@ -122,10 +124,8 @@ struct ksmbd_file_table {
|
||||
struct idr *idr;
|
||||
};
|
||||
|
||||
static inline bool HAS_FILE_ID(unsigned long long req)
|
||||
static inline bool has_file_id(u64 id)
|
||||
{
|
||||
unsigned int id = (unsigned int)req;
|
||||
|
||||
return id < KSMBD_NO_FID;
|
||||
}
|
||||
|
||||
@ -136,11 +136,11 @@ static inline bool ksmbd_stream_fd(struct ksmbd_file *fp)
|
||||
|
||||
int ksmbd_init_file_table(struct ksmbd_file_table *ft);
|
||||
void ksmbd_destroy_file_table(struct ksmbd_file_table *ft);
|
||||
int ksmbd_close_fd(struct ksmbd_work *work, unsigned int id);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, unsigned int id);
|
||||
struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, unsigned int id);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, unsigned int id,
|
||||
unsigned int pid);
|
||||
int ksmbd_close_fd(struct ksmbd_work *work, u64 id);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id);
|
||||
struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
|
||||
u64 pid);
|
||||
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_fd_cguid(char *cguid);
|
||||
|
Loading…
x
Reference in New Issue
Block a user