eight SMB3 server fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmiHqYkACgkQiiy9cAdy T1FfyQwAi+luMNvR8p9rH3zNVk+WN/a4vV3suJFuc6Bl6kXFfeNU0DFIB2ZCqAmz lk0N5B/dAd71IpNkTtIX2nZiJpRIBzTy5xAnwARq2LdrDi6ipNSKOv4qfOEMeufl ehfkqJL/9YQWJv/78Tntfuub2V3t479lpVRDp5hGAwZB4i9KZcVew7ifJJhCoUSh 9NxcRD6AefeZTZaoTyKXayDCTjEn9N7Q6sXOTsSnLSX+e2nIDobFh+Sm1sDcSHMh 2BH9a2Eg9CAZkLj6/53sIYUR4LLJjFMeDRpsGa4RZW0QA23WYJqR+R2Ouc5eCkBD OS79J5GAbag0RqujLqbl4QXFJRJgW6epB6cCOCjqqo5fQPQa9TIPem2iB5T1NHTg yMiuJk+qRX1vqyt8QI05yromSYKY7QBqgKzfkjv7054N1XfyUK/99Y+lX5t2nMZ7 Fodxdaxrmk78cUpyaCbTLlW7zrkvMK6hQRQ2h++Q2RrYZ8mo+ciR13B6nftR3sdA mewSF+yO =DRH3 -----END PGP SIGNATURE----- Merge tag 'v6.17-rc-smb3-server-fixes' of git://git.samba.org/ksmbd Pull smb server updates from Steve French: - Fix mtime/ctime reporting issue - Auth fixes, including two session setup race bugs reported by ZDI - Locking improvement in query directory - Fix for potential deadlock in creating hardlinks - Improvements to path name processing * tag 'v6.17-rc-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix corrupted mtime and ctime in smb2_open ksmbd: fix Preauh_HashValue race condition ksmbd: check return value of xa_store() in krb5_authenticate ksmbd: fix null pointer dereference error in generate_encryptionkey smb/server: add ksmbd_vfs_kern_path() smb/server: avoid deadlock when linking with ReplaceIfExists smb/server: simplify ksmbd_vfs_kern_path_locked() smb/server: use lookup_one_unlocked()pull/1309/head
commit
e5cf61fa6e
|
|
@ -1594,7 +1594,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
|||
struct ksmbd_conn *conn = work->conn;
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
char *in_blob, *out_blob;
|
||||
struct channel *chann = NULL;
|
||||
struct channel *chann = NULL, *old;
|
||||
u64 prev_sess_id;
|
||||
int in_len, out_len;
|
||||
int retval;
|
||||
|
|
@ -1621,11 +1621,24 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
|||
|
||||
rsp->SecurityBufferLength = cpu_to_le16(out_len);
|
||||
|
||||
if ((conn->sign || server_conf.enforced_signing) ||
|
||||
/*
|
||||
* If session state is SMB2_SESSION_VALID, We can assume
|
||||
* that it is reauthentication. And the user/password
|
||||
* has been verified, so return it here.
|
||||
*/
|
||||
if (sess->state == SMB2_SESSION_VALID) {
|
||||
if (conn->binding)
|
||||
goto binding_session;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((rsp->SessionFlags != SMB2_SESSION_FLAG_IS_GUEST_LE &&
|
||||
(conn->sign || server_conf.enforced_signing)) ||
|
||||
(req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
|
||||
sess->sign = true;
|
||||
|
||||
if (smb3_encryption_negotiated(conn)) {
|
||||
if (smb3_encryption_negotiated(conn) &&
|
||||
!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
|
||||
retval = conn->ops->generate_encryptionkey(conn, sess);
|
||||
if (retval) {
|
||||
ksmbd_debug(SMB,
|
||||
|
|
@ -1638,6 +1651,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
|||
sess->sign = false;
|
||||
}
|
||||
|
||||
binding_session:
|
||||
if (conn->dialect >= SMB30_PROT_ID) {
|
||||
chann = lookup_chann_list(sess, conn);
|
||||
if (!chann) {
|
||||
|
|
@ -1646,7 +1660,12 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
|||
return -ENOMEM;
|
||||
|
||||
chann->conn = conn;
|
||||
xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP);
|
||||
old = xa_store(&sess->ksmbd_chann_list, (long)conn,
|
||||
chann, KSMBD_DEFAULT_GFP);
|
||||
if (xa_is_err(old)) {
|
||||
kfree(chann);
|
||||
return xa_err(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1833,8 +1852,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
|||
ksmbd_conn_set_good(conn);
|
||||
sess->state = SMB2_SESSION_VALID;
|
||||
}
|
||||
kfree(sess->Preauth_HashValue);
|
||||
sess->Preauth_HashValue = NULL;
|
||||
} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
|
||||
if (negblob->MessageType == NtLmNegotiate) {
|
||||
rc = ntlm_negotiate(work, negblob, negblob_len, rsp);
|
||||
|
|
@ -1861,8 +1878,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
|||
kfree(preauth_sess);
|
||||
}
|
||||
}
|
||||
kfree(sess->Preauth_HashValue);
|
||||
sess->Preauth_HashValue = NULL;
|
||||
} else {
|
||||
pr_info_ratelimited("Unknown NTLMSSP message type : 0x%x\n",
|
||||
le32_to_cpu(negblob->MessageType));
|
||||
|
|
@ -2581,7 +2596,7 @@ static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
|
|||
}
|
||||
}
|
||||
|
||||
static int smb2_creat(struct ksmbd_work *work, struct path *parent_path,
|
||||
static int smb2_creat(struct ksmbd_work *work,
|
||||
struct path *path, char *name, int open_flags,
|
||||
umode_t posix_mode, bool is_dir)
|
||||
{
|
||||
|
|
@ -2610,7 +2625,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *parent_path,
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = ksmbd_vfs_kern_path_locked(work, name, 0, parent_path, path, 0);
|
||||
rc = ksmbd_vfs_kern_path(work, name, 0, path, 0);
|
||||
if (rc) {
|
||||
pr_err("cannot get linux path (%s), err = %d\n",
|
||||
name, rc);
|
||||
|
|
@ -2860,7 +2875,7 @@ int smb2_open(struct ksmbd_work *work)
|
|||
struct ksmbd_tree_connect *tcon = work->tcon;
|
||||
struct smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp;
|
||||
struct path path, parent_path;
|
||||
struct path path;
|
||||
struct ksmbd_share_config *share = tcon->share_conf;
|
||||
struct ksmbd_file *fp = NULL;
|
||||
struct file *filp = NULL;
|
||||
|
|
@ -3116,8 +3131,8 @@ int smb2_open(struct ksmbd_work *work)
|
|||
goto err_out2;
|
||||
}
|
||||
|
||||
rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,
|
||||
&parent_path, &path, 1);
|
||||
rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS,
|
||||
&path, 1);
|
||||
if (!rc) {
|
||||
file_present = true;
|
||||
|
||||
|
|
@ -3238,7 +3253,7 @@ int smb2_open(struct ksmbd_work *work)
|
|||
|
||||
/*create file if not present */
|
||||
if (!file_present) {
|
||||
rc = smb2_creat(work, &parent_path, &path, name, open_flags,
|
||||
rc = smb2_creat(work, &path, name, open_flags,
|
||||
posix_mode,
|
||||
req->CreateOptions & FILE_DIRECTORY_FILE_LE);
|
||||
if (rc) {
|
||||
|
|
@ -3443,7 +3458,7 @@ int smb2_open(struct ksmbd_work *work)
|
|||
}
|
||||
|
||||
if (file_present || created)
|
||||
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
|
||||
path_put(&path);
|
||||
|
||||
if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
|
||||
!fp->attrib_only && !stream_name) {
|
||||
|
|
@ -3724,7 +3739,7 @@ reconnected_fp:
|
|||
|
||||
err_out:
|
||||
if (rc && (file_present || created))
|
||||
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
|
||||
path_put(&path);
|
||||
|
||||
err_out1:
|
||||
ksmbd_revert_fsids(work);
|
||||
|
|
@ -4108,20 +4123,6 @@ struct smb2_query_dir_private {
|
|||
int info_level;
|
||||
};
|
||||
|
||||
static void lock_dir(struct ksmbd_file *dir_fp)
|
||||
{
|
||||
struct dentry *dir = dir_fp->filp->f_path.dentry;
|
||||
|
||||
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
|
||||
}
|
||||
|
||||
static void unlock_dir(struct ksmbd_file *dir_fp)
|
||||
{
|
||||
struct dentry *dir = dir_fp->filp->f_path.dentry;
|
||||
|
||||
inode_unlock(d_inode(dir));
|
||||
}
|
||||
|
||||
static int process_query_dir_entries(struct smb2_query_dir_private *priv)
|
||||
{
|
||||
struct mnt_idmap *idmap = file_mnt_idmap(priv->dir_fp->filp);
|
||||
|
|
@ -4136,12 +4137,10 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv)
|
|||
if (dentry_name(priv->d_info, priv->info_level))
|
||||
return -EINVAL;
|
||||
|
||||
lock_dir(priv->dir_fp);
|
||||
dent = lookup_one(idmap,
|
||||
&QSTR_LEN(priv->d_info->name,
|
||||
priv->d_info->name_len),
|
||||
priv->dir_fp->filp->f_path.dentry);
|
||||
unlock_dir(priv->dir_fp);
|
||||
dent = lookup_one_unlocked(idmap,
|
||||
&QSTR_LEN(priv->d_info->name,
|
||||
priv->d_info->name_len),
|
||||
priv->dir_fp->filp->f_path.dentry);
|
||||
|
||||
if (IS_ERR(dent)) {
|
||||
ksmbd_debug(SMB, "Cannot lookup `%s' [%ld]\n",
|
||||
|
|
@ -6052,8 +6051,7 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||
struct nls_table *local_nls)
|
||||
{
|
||||
char *link_name = NULL, *target_name = NULL, *pathname = NULL;
|
||||
struct path path, parent_path;
|
||||
bool file_present = false;
|
||||
struct path path;
|
||||
int rc;
|
||||
|
||||
if (buf_len < (u64)sizeof(struct smb2_file_link_info) +
|
||||
|
|
@ -6082,15 +6080,12 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||
|
||||
ksmbd_debug(SMB, "target name is %s\n", target_name);
|
||||
rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS,
|
||||
&parent_path, &path, 0);
|
||||
&path, 0);
|
||||
if (rc) {
|
||||
if (rc != -ENOENT)
|
||||
goto out;
|
||||
} else
|
||||
file_present = true;
|
||||
|
||||
if (file_info->ReplaceIfExists) {
|
||||
if (file_present) {
|
||||
} else {
|
||||
if (file_info->ReplaceIfExists) {
|
||||
rc = ksmbd_vfs_remove_file(work, &path);
|
||||
if (rc) {
|
||||
rc = -EINVAL;
|
||||
|
|
@ -6098,21 +6093,17 @@ static int smb2_create_link(struct ksmbd_work *work,
|
|||
link_name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (file_present) {
|
||||
} else {
|
||||
rc = -EEXIST;
|
||||
ksmbd_debug(SMB, "link already exists\n");
|
||||
goto out;
|
||||
}
|
||||
ksmbd_vfs_kern_path_unlock(&path);
|
||||
}
|
||||
|
||||
rc = ksmbd_vfs_link(work, target_name, link_name);
|
||||
if (rc)
|
||||
rc = -EINVAL;
|
||||
out:
|
||||
if (file_present)
|
||||
ksmbd_vfs_kern_path_unlock(&parent_path, &path);
|
||||
|
||||
if (!IS_ERR(link_name))
|
||||
kfree(link_name);
|
||||
|
|
|
|||
|
|
@ -66,13 +66,12 @@ int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
|
||||
char *pathname, unsigned int flags,
|
||||
struct path *parent_path,
|
||||
struct path *path)
|
||||
static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
|
||||
char *pathname, unsigned int flags,
|
||||
struct path *path, bool do_lock)
|
||||
{
|
||||
struct qstr last;
|
||||
struct filename *filename;
|
||||
struct filename *filename __free(putname) = NULL;
|
||||
struct path *root_share_path = &share_conf->vfs_path;
|
||||
int err, type;
|
||||
struct dentry *d;
|
||||
|
|
@ -89,51 +88,57 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
|
|||
return PTR_ERR(filename);
|
||||
|
||||
err = vfs_path_parent_lookup(filename, flags,
|
||||
parent_path, &last, &type,
|
||||
path, &last, &type,
|
||||
root_share_path);
|
||||
if (err) {
|
||||
putname(filename);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (unlikely(type != LAST_NORM)) {
|
||||
path_put(parent_path);
|
||||
putname(filename);
|
||||
path_put(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = mnt_want_write(parent_path->mnt);
|
||||
if (err) {
|
||||
path_put(parent_path);
|
||||
putname(filename);
|
||||
if (do_lock) {
|
||||
err = mnt_want_write(path->mnt);
|
||||
if (err) {
|
||||
path_put(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
|
||||
d = lookup_one_qstr_excl(&last, path->dentry, 0);
|
||||
|
||||
if (!IS_ERR(d)) {
|
||||
dput(path->dentry);
|
||||
path->dentry = d;
|
||||
return 0;
|
||||
}
|
||||
inode_unlock(path->dentry->d_inode);
|
||||
mnt_drop_write(path->mnt);
|
||||
path_put(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT);
|
||||
d = lookup_one_qstr_excl(&last, parent_path->dentry, 0);
|
||||
if (IS_ERR(d))
|
||||
goto err_out;
|
||||
|
||||
d = lookup_noperm_unlocked(&last, path->dentry);
|
||||
if (!IS_ERR(d) && d_is_negative(d)) {
|
||||
dput(d);
|
||||
d = ERR_PTR(-ENOENT);
|
||||
}
|
||||
if (IS_ERR(d)) {
|
||||
path_put(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
dput(path->dentry);
|
||||
path->dentry = d;
|
||||
path->mnt = mntget(parent_path->mnt);
|
||||
|
||||
if (test_share_config_flag(share_conf, KSMBD_SHARE_FLAG_CROSSMNT)) {
|
||||
err = follow_down(path, 0);
|
||||
if (err < 0) {
|
||||
path_put(path);
|
||||
goto err_out;
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
putname(filename);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
inode_unlock(d_inode(parent_path->dentry));
|
||||
mnt_drop_write(parent_path->mnt);
|
||||
path_put(parent_path);
|
||||
putname(filename);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap,
|
||||
|
|
@ -548,7 +553,8 @@ int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = vfs_getattr(path, stat, STATX_BTIME, AT_STATX_SYNC_AS_STAT);
|
||||
err = vfs_getattr(path, stat, STATX_BASIC_STATS | STATX_BTIME,
|
||||
AT_STATX_SYNC_AS_STAT);
|
||||
if (err)
|
||||
pr_err("getattr failed, err %d\n", err);
|
||||
return err;
|
||||
|
|
@ -1198,104 +1204,114 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_vfs_kern_path_locked() - lookup a file and get path info
|
||||
* @work: work
|
||||
* @name: file path that is relative to share
|
||||
* @flags: lookup flags
|
||||
* @parent_path: if lookup succeed, return parent_path info
|
||||
* @path: if lookup succeed, return path info
|
||||
* @caseless: caseless filename lookup
|
||||
*
|
||||
* Return: 0 on success, otherwise error
|
||||
*/
|
||||
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
|
||||
unsigned int flags, struct path *parent_path,
|
||||
struct path *path, bool caseless)
|
||||
static
|
||||
int __ksmbd_vfs_kern_path(struct ksmbd_work *work, char *filepath,
|
||||
unsigned int flags,
|
||||
struct path *path, bool caseless, bool do_lock)
|
||||
{
|
||||
struct ksmbd_share_config *share_conf = work->tcon->share_conf;
|
||||
struct path parent_path;
|
||||
size_t path_len, remain_len;
|
||||
int err;
|
||||
|
||||
err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, parent_path,
|
||||
path);
|
||||
if (!err)
|
||||
return 0;
|
||||
retry:
|
||||
err = ksmbd_vfs_path_lookup(share_conf, filepath, flags, path, do_lock);
|
||||
if (!err || !caseless)
|
||||
return err;
|
||||
|
||||
if (caseless) {
|
||||
char *filepath;
|
||||
size_t path_len, remain_len;
|
||||
path_len = strlen(filepath);
|
||||
remain_len = path_len;
|
||||
|
||||
filepath = name;
|
||||
path_len = strlen(filepath);
|
||||
remain_len = path_len;
|
||||
parent_path = share_conf->vfs_path;
|
||||
path_get(&parent_path);
|
||||
|
||||
*parent_path = share_conf->vfs_path;
|
||||
path_get(parent_path);
|
||||
while (d_can_lookup(parent_path.dentry)) {
|
||||
char *filename = filepath + path_len - remain_len;
|
||||
char *next = strchrnul(filename, '/');
|
||||
size_t filename_len = next - filename;
|
||||
bool is_last = !next[0];
|
||||
|
||||
while (d_can_lookup(parent_path->dentry)) {
|
||||
char *filename = filepath + path_len - remain_len;
|
||||
char *next = strchrnul(filename, '/');
|
||||
size_t filename_len = next - filename;
|
||||
bool is_last = !next[0];
|
||||
if (filename_len == 0)
|
||||
break;
|
||||
|
||||
if (filename_len == 0)
|
||||
break;
|
||||
|
||||
err = ksmbd_vfs_lookup_in_dir(parent_path, filename,
|
||||
filename_len,
|
||||
work->conn->um);
|
||||
if (err)
|
||||
goto out2;
|
||||
|
||||
next[0] = '\0';
|
||||
|
||||
err = vfs_path_lookup(share_conf->vfs_path.dentry,
|
||||
share_conf->vfs_path.mnt,
|
||||
filepath,
|
||||
flags,
|
||||
path);
|
||||
if (!is_last)
|
||||
next[0] = '/';
|
||||
if (err)
|
||||
goto out2;
|
||||
else if (is_last)
|
||||
goto out1;
|
||||
path_put(parent_path);
|
||||
*parent_path = *path;
|
||||
|
||||
remain_len -= filename_len + 1;
|
||||
err = ksmbd_vfs_lookup_in_dir(&parent_path, filename,
|
||||
filename_len,
|
||||
work->conn->um);
|
||||
path_put(&parent_path);
|
||||
if (err)
|
||||
goto out;
|
||||
if (is_last) {
|
||||
caseless = false;
|
||||
goto retry;
|
||||
}
|
||||
next[0] = '\0';
|
||||
|
||||
err = -EINVAL;
|
||||
out2:
|
||||
path_put(parent_path);
|
||||
err = vfs_path_lookup(share_conf->vfs_path.dentry,
|
||||
share_conf->vfs_path.mnt,
|
||||
filepath,
|
||||
flags,
|
||||
&parent_path);
|
||||
next[0] = '/';
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
remain_len -= filename_len + 1;
|
||||
}
|
||||
|
||||
out1:
|
||||
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);
|
||||
if (err) {
|
||||
mnt_drop_write(parent_path->mnt);
|
||||
path_put(path);
|
||||
path_put(parent_path);
|
||||
}
|
||||
}
|
||||
err = -EINVAL;
|
||||
path_put(&parent_path);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path)
|
||||
/**
|
||||
* ksmbd_vfs_kern_path() - lookup a file and get path info
|
||||
* @work: work
|
||||
* @filepath: file path that is relative to share
|
||||
* @flags: lookup flags
|
||||
* @path: if lookup succeed, return path info
|
||||
* @caseless: caseless filename lookup
|
||||
*
|
||||
* Perform the lookup, possibly crossing over any mount point.
|
||||
* On return no locks will be held and write-access to filesystem
|
||||
* won't have been checked.
|
||||
* Return: 0 if file was found, otherwise error
|
||||
*/
|
||||
int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *filepath,
|
||||
unsigned int flags,
|
||||
struct path *path, bool caseless)
|
||||
{
|
||||
inode_unlock(d_inode(parent_path->dentry));
|
||||
mnt_drop_write(parent_path->mnt);
|
||||
return __ksmbd_vfs_kern_path(work, filepath, flags, path,
|
||||
caseless, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_vfs_kern_path_locked() - lookup a file and get path info
|
||||
* @work: work
|
||||
* @filepath: file path that is relative to share
|
||||
* @flags: lookup flags
|
||||
* @path: if lookup succeed, return path info
|
||||
* @caseless: caseless filename lookup
|
||||
*
|
||||
* Perform the lookup, but don't cross over any mount point.
|
||||
* On return the parent of path->dentry will be locked and write-access to
|
||||
* filesystem will have been gained.
|
||||
* Return: 0 on if file was found, otherwise error
|
||||
*/
|
||||
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *filepath,
|
||||
unsigned int flags,
|
||||
struct path *path, bool caseless)
|
||||
{
|
||||
return __ksmbd_vfs_kern_path(work, filepath, flags, path,
|
||||
caseless, true);
|
||||
}
|
||||
|
||||
void ksmbd_vfs_kern_path_unlock(struct path *path)
|
||||
{
|
||||
/* While lock is still held, ->d_parent is safe */
|
||||
inode_unlock(d_inode(path->dentry->d_parent));
|
||||
mnt_drop_write(path->mnt);
|
||||
path_put(path);
|
||||
path_put(parent_path);
|
||||
}
|
||||
|
||||
struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
|
||||
|
|
|
|||
|
|
@ -117,10 +117,13 @@ int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
|
|||
int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
|
||||
const struct path *path, char *attr_name,
|
||||
bool get_write);
|
||||
int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name,
|
||||
unsigned int flags,
|
||||
struct path *path, bool caseless);
|
||||
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
|
||||
unsigned int flags, struct path *parent_path,
|
||||
unsigned int flags,
|
||||
struct path *path, bool caseless);
|
||||
void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path);
|
||||
void ksmbd_vfs_kern_path_unlock(struct path *path);
|
||||
struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
|
||||
const char *name,
|
||||
unsigned int flags,
|
||||
|
|
|
|||
Loading…
Reference in New Issue