mirror of
https://github.com/torvalds/linux.git
synced 2025-12-01 07:26:02 +07:00
Merge tag 'v6.18-rc-part2-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull more smb client updates from Steve French: - fix i_size in fallocate - two truncate fixes - utime fix - minor cleanups - SMB1 fixes - improve error check in read - improve perf of copy file_range (copy_chunk) * tag 'v6.18-rc-part2-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal version number cifs: Add comments for DeletePending assignments in open functions cifs: Add fallback code path for cifs_mkdir_setinfo() cifs: Allow fallback code in smb_set_file_info() also for directories cifs: Query EA $LXMOD in cifs_query_path_info() for WSL reparse points smb: client: remove cfids_invalidation_worker smb: client: remove redudant assignment in cifs_strict_fsync() smb: client: fix race with fallocate(2) and AIO+DIO smb: client: fix missing timestamp updates after utime(2) smb: client: fix missing timestamp updates after ftruncate(2) smb: client: fix missing timestamp updates with O_TRUNC cifs: Fix copy_to_iter return value check smb: client: batch SRV_COPYCHUNK entries to cut round trips smb: client: Omit an if branch in smb2_find_smb_tcon() smb: client: Return directly after a failed genlmsg_new() in cifs_swn_send_register_message() smb: client: Use common code in cifs_do_create() smb: client: Improve unlocking of a mutex in cifs_get_swn_reg() smb: client: Return a status code only as a constant in cifs_spnego_key_instantiate() smb: client: Use common code in cifs_lookup() smb: client: Reduce the scopes for a few variables in two functions
This commit is contained in:
@@ -562,8 +562,8 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
|
||||
/*
|
||||
* Mark all the cfids as closed, and move them to the cfids->dying list.
|
||||
* They'll be cleaned up later by cfids_invalidation_worker. Take
|
||||
* a reference to each cfid during this process.
|
||||
* They'll be cleaned up by laundromat. Take a reference to each cfid
|
||||
* during this process.
|
||||
*/
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
@@ -580,12 +580,11 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
} else
|
||||
kref_get(&cfid->refcount);
|
||||
}
|
||||
/*
|
||||
* Queue dropping of the dentries once locks have been dropped
|
||||
*/
|
||||
if (!list_empty(&cfids->dying))
|
||||
queue_work(cfid_put_wq, &cfids->invalidation_work);
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
/* run laundromat unconditionally now as there might have been previously queued work */
|
||||
mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
|
||||
flush_delayed_work(&cfids->laundromat_work);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -715,25 +714,6 @@ static void free_cached_dir(struct cached_fid *cfid)
|
||||
kfree(cfid);
|
||||
}
|
||||
|
||||
static void cfids_invalidation_worker(struct work_struct *work)
|
||||
{
|
||||
struct cached_fids *cfids = container_of(work, struct cached_fids,
|
||||
invalidation_work);
|
||||
struct cached_fid *cfid, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
/* move cfids->dying to the local list */
|
||||
list_cut_before(&entry, &cfids->dying, &cfids->dying);
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
/* Drop the ref-count acquired in invalidate_all_cached_dirs */
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
}
|
||||
|
||||
static void cfids_laundromat_worker(struct work_struct *work)
|
||||
{
|
||||
struct cached_fids *cfids;
|
||||
@@ -743,6 +723,9 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
||||
cfids = container_of(work, struct cached_fids, laundromat_work.work);
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
/* move cfids->dying to the local list */
|
||||
list_cut_before(&entry, &cfids->dying, &cfids->dying);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
if (cfid->last_access_time &&
|
||||
time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) {
|
||||
@@ -796,7 +779,6 @@ struct cached_fids *init_cached_dirs(void)
|
||||
INIT_LIST_HEAD(&cfids->entries);
|
||||
INIT_LIST_HEAD(&cfids->dying);
|
||||
|
||||
INIT_WORK(&cfids->invalidation_work, cfids_invalidation_worker);
|
||||
INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
|
||||
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
||||
dir_cache_timeout * HZ);
|
||||
@@ -820,7 +802,6 @@ void free_cached_dirs(struct cached_fids *cfids)
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&cfids->laundromat_work);
|
||||
cancel_work_sync(&cfids->invalidation_work);
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
|
||||
@@ -62,7 +62,6 @@ struct cached_fids {
|
||||
int num_entries;
|
||||
struct list_head entries;
|
||||
struct list_head dying;
|
||||
struct work_struct invalidation_work;
|
||||
struct delayed_work laundromat_work;
|
||||
/* aggregate accounting for all cached dirents under this tcon */
|
||||
atomic_long_t total_dirents_entries;
|
||||
|
||||
@@ -24,20 +24,14 @@ static const struct cred *spnego_cred;
|
||||
static int
|
||||
cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
{
|
||||
char *payload;
|
||||
int ret;
|
||||
char *payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
|
||||
|
||||
ret = -ENOMEM;
|
||||
payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
goto error;
|
||||
return -ENOMEM;
|
||||
|
||||
/* attach the data */
|
||||
key->payload.data[0] = payload;
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -82,10 +82,8 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
|
||||
int ret;
|
||||
|
||||
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER);
|
||||
if (hdr == NULL) {
|
||||
@@ -172,7 +170,6 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
|
||||
nlmsg_fail:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
nlmsg_free(skb);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -313,17 +310,15 @@ static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
|
||||
reg = cifs_find_swn_reg(tcon);
|
||||
if (!IS_ERR(reg)) {
|
||||
kref_get(®->ref_count);
|
||||
mutex_unlock(&cifs_swnreg_idr_mutex);
|
||||
return reg;
|
||||
goto unlock;
|
||||
} else if (PTR_ERR(reg) != -EEXIST) {
|
||||
mutex_unlock(&cifs_swnreg_idr_mutex);
|
||||
return reg;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC);
|
||||
if (reg == NULL) {
|
||||
mutex_unlock(&cifs_swnreg_idr_mutex);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto fail_unlock;
|
||||
}
|
||||
|
||||
kref_init(®->ref_count);
|
||||
@@ -354,7 +349,7 @@ static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
|
||||
reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT);
|
||||
|
||||
reg->tcon = tcon;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&cifs_swnreg_idr_mutex);
|
||||
|
||||
return reg;
|
||||
@@ -365,6 +360,7 @@ fail_idr:
|
||||
idr_remove(&cifs_swnreg_idr, reg->id);
|
||||
fail:
|
||||
kfree(reg);
|
||||
fail_unlock:
|
||||
mutex_unlock(&cifs_swnreg_idr_mutex);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -392,11 +392,27 @@ static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
|
||||
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct inode *inode = file_inode(file);
|
||||
int rc;
|
||||
|
||||
if (server->ops->fallocate)
|
||||
return server->ops->fallocate(file, tcon, mode, off, len);
|
||||
if (!server->ops->fallocate)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
rc = inode_lock_killable(inode);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
|
||||
rc = file_modified(file);
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
|
||||
rc = server->ops->fallocate(file, tcon, mode, off, len);
|
||||
|
||||
out_unlock:
|
||||
inode_unlock(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_permission(struct mnt_idmap *idmap,
|
||||
|
||||
@@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
/* when changing internal version - update following two lines at same time */
|
||||
#define SMB3_PRODUCT_BUILD 56
|
||||
#define CIFS_VERSION "2.56"
|
||||
#define SMB3_PRODUCT_BUILD 57
|
||||
#define CIFS_VERSION "2.57"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
||||
@@ -1566,6 +1566,11 @@ struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
|
||||
void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_hdlr,
|
||||
bool offload);
|
||||
void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
|
||||
int cifs_file_flush(const unsigned int xid, struct inode *inode,
|
||||
struct cifsFileInfo *cfile);
|
||||
int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
|
||||
const char *full_path, struct cifsFileInfo *open_file,
|
||||
loff_t size);
|
||||
|
||||
#define CIFS_CACHE_READ_FLG 1
|
||||
#define CIFS_CACHE_HANDLE_FLG 2
|
||||
|
||||
@@ -1163,7 +1163,7 @@ OldOpenRetry:
|
||||
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
|
||||
pfile_info->EndOfFile = pfile_info->AllocationSize;
|
||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||
pfile_info->DeletePending = 0;
|
||||
pfile_info->DeletePending = 0; /* successful open = not delete pending */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1288,7 +1288,7 @@ openRetry:
|
||||
buf->AllocationSize = rsp->AllocationSize;
|
||||
buf->EndOfFile = rsp->EndOfFile;
|
||||
buf->NumberOfLinks = cpu_to_le32(1);
|
||||
buf->DeletePending = 0;
|
||||
buf->DeletePending = 0; /* successful open = not delete pending */
|
||||
}
|
||||
|
||||
cifs_buf_release(req);
|
||||
|
||||
@@ -200,8 +200,8 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
|
||||
|
||||
full_path = build_path_from_dentry(direntry, page);
|
||||
if (IS_ERR(full_path)) {
|
||||
free_dentry_path(page);
|
||||
return PTR_ERR(full_path);
|
||||
rc = PTR_ERR(full_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we're caching, we need to be able to fill in around partial writes. */
|
||||
@@ -678,7 +678,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
const char *full_path;
|
||||
void *page;
|
||||
int retry_count = 0;
|
||||
struct cached_fid *cfid = NULL;
|
||||
struct dentry *de;
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
@@ -690,16 +690,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
free_xid(xid);
|
||||
return ERR_CAST(tlink);
|
||||
de = ERR_CAST(tlink);
|
||||
goto free_xid;
|
||||
}
|
||||
pTcon = tlink_tcon(tlink);
|
||||
|
||||
rc = check_name(direntry, pTcon);
|
||||
if (unlikely(rc)) {
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid(xid);
|
||||
return ERR_PTR(rc);
|
||||
de = ERR_PTR(rc);
|
||||
goto put_tlink;
|
||||
}
|
||||
|
||||
/* can not grab the rename sem here since it would
|
||||
@@ -708,15 +707,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
page = alloc_dentry_path();
|
||||
full_path = build_path_from_dentry(direntry, page);
|
||||
if (IS_ERR(full_path)) {
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid(xid);
|
||||
free_dentry_path(page);
|
||||
return ERR_CAST(full_path);
|
||||
de = ERR_CAST(full_path);
|
||||
goto free_dentry_path;
|
||||
}
|
||||
|
||||
if (d_really_is_positive(direntry)) {
|
||||
cifs_dbg(FYI, "non-NULL inode in lookup\n");
|
||||
} else {
|
||||
struct cached_fid *cfid = NULL;
|
||||
|
||||
cifs_dbg(FYI, "NULL inode in lookup\n");
|
||||
|
||||
/*
|
||||
@@ -775,25 +774,27 @@ again:
|
||||
}
|
||||
|
||||
out:
|
||||
de = d_splice_alias(newInode, direntry);
|
||||
free_dentry_path:
|
||||
free_dentry_path(page);
|
||||
put_tlink:
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid:
|
||||
free_xid(xid);
|
||||
return d_splice_alias(newInode, direntry);
|
||||
return de;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_d_revalidate(struct inode *dir, const struct qstr *name,
|
||||
struct dentry *direntry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct cached_fid *cfid;
|
||||
int rc;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
if (d_really_is_positive(direntry)) {
|
||||
inode = d_inode(direntry);
|
||||
int rc;
|
||||
struct inode *inode = d_inode(direntry);
|
||||
|
||||
if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
|
||||
CIFS_I(inode)->time = 0; /* force reval */
|
||||
|
||||
@@ -836,6 +837,7 @@ cifs_d_revalidate(struct inode *dir, const struct qstr *name,
|
||||
} else {
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dir->i_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct cached_fid *cfid;
|
||||
|
||||
if (!open_cached_dir_by_dentry(tcon, direntry->d_parent, &cfid)) {
|
||||
/*
|
||||
|
||||
@@ -952,6 +952,66 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
|
||||
}
|
||||
}
|
||||
|
||||
int cifs_file_flush(const unsigned int xid, struct inode *inode,
|
||||
struct cifsFileInfo *cfile)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifs_tcon *tcon;
|
||||
int rc;
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
|
||||
return 0;
|
||||
|
||||
if (cfile && (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE)) {
|
||||
tcon = tlink_tcon(cfile->tlink);
|
||||
return tcon->ses->server->ops->flush(xid, tcon,
|
||||
&cfile->fid);
|
||||
}
|
||||
rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile);
|
||||
if (!rc) {
|
||||
tcon = tlink_tcon(cfile->tlink);
|
||||
rc = tcon->ses->server->ops->flush(xid, tcon, &cfile->fid);
|
||||
cifsFileInfo_put(cfile);
|
||||
} else if (rc == -EBADF) {
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
|
||||
{
|
||||
struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct cifsFileInfo *cfile = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_tcon *tcon;
|
||||
int rc;
|
||||
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (is_interrupt_error(rc))
|
||||
return -ERESTARTSYS;
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
|
||||
cfile = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
|
||||
rc = cifs_file_flush(xid, inode, cfile);
|
||||
if (!rc) {
|
||||
if (cfile) {
|
||||
tcon = tlink_tcon(cfile->tlink);
|
||||
server = tcon->ses->server;
|
||||
rc = server->ops->set_file_size(xid, tcon,
|
||||
cfile, 0, false);
|
||||
}
|
||||
if (!rc) {
|
||||
netfs_resize_file(&cinode->netfs, 0, true);
|
||||
cifs_setsize(inode, 0);
|
||||
inode->i_blocks = 0;
|
||||
}
|
||||
}
|
||||
if (cfile)
|
||||
cifsFileInfo_put(cfile);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_open(struct inode *inode, struct file *file)
|
||||
|
||||
{
|
||||
@@ -1004,6 +1064,12 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
file->f_op = &cifs_file_direct_ops;
|
||||
}
|
||||
|
||||
if (file->f_flags & O_TRUNC) {
|
||||
rc = cifs_do_truncate(xid, file_dentry(file));
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the cached handle as SMB2 close is deferred */
|
||||
if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) {
|
||||
rc = cifs_get_writable_path(tcon, full_path,
|
||||
@@ -2685,13 +2751,10 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
|
||||
int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
||||
int datasync)
|
||||
{
|
||||
unsigned int xid;
|
||||
int rc = 0;
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifsFileInfo *smbfile = file->private_data;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
unsigned int xid;
|
||||
int rc;
|
||||
|
||||
rc = file_write_and_wait_range(file, start, end);
|
||||
if (rc) {
|
||||
@@ -2699,39 +2762,15 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
||||
return rc;
|
||||
}
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n",
|
||||
file, datasync);
|
||||
cifs_dbg(FYI, "%s: name=%pD datasync=0x%x\n", __func__, file, datasync);
|
||||
|
||||
if (!CIFS_CACHE_READ(CIFS_I(inode))) {
|
||||
rc = cifs_zap_mapping(inode);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc);
|
||||
rc = 0; /* don't care about it in fsync */
|
||||
}
|
||||
cifs_dbg(FYI, "%s: invalidate mapping: rc = %d\n", __func__, rc);
|
||||
}
|
||||
|
||||
tcon = tlink_tcon(smbfile->tlink);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
||||
server = tcon->ses->server;
|
||||
if (server->ops->flush == NULL) {
|
||||
rc = -ENOSYS;
|
||||
goto strict_fsync_exit;
|
||||
}
|
||||
|
||||
if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
|
||||
smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
|
||||
if (smbfile) {
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
cifsFileInfo_put(smbfile);
|
||||
} else
|
||||
cifs_dbg(FYI, "ignore fsync for file not open for write\n");
|
||||
} else
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
}
|
||||
|
||||
strict_fsync_exit:
|
||||
xid = get_xid();
|
||||
rc = cifs_file_flush(xid, inode, smbfile);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3007,28 +3007,25 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
|
||||
|
||||
void cifs_setsize(struct inode *inode, loff_t offset)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
i_size_write(inode, offset);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
/* Cached inode must be refreshed on truncate */
|
||||
cifs_i->time = 0;
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
truncate_pagecache(inode, offset);
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
unsigned int xid, const char *full_path, struct dentry *dentry)
|
||||
int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
|
||||
const char *full_path, struct cifsFileInfo *open_file,
|
||||
loff_t size)
|
||||
{
|
||||
int rc;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||
struct tcon_link *tlink = NULL;
|
||||
struct cifs_tcon *tcon = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
int rc = -EINVAL;
|
||||
|
||||
/*
|
||||
* To avoid spurious oplock breaks from server, in the case of
|
||||
@@ -3039,19 +3036,25 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
* writebehind data than the SMB timeout for the SetPathInfo
|
||||
* request would allow
|
||||
*/
|
||||
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
|
||||
if (open_file) {
|
||||
if (open_file && (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE)) {
|
||||
tcon = tlink_tcon(open_file->tlink);
|
||||
server = tcon->ses->server;
|
||||
if (server->ops->set_file_size)
|
||||
rc = server->ops->set_file_size(xid, tcon, open_file,
|
||||
attrs->ia_size, false);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
cifsFileInfo_put(open_file);
|
||||
cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc);
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
rc = server->ops->set_file_size(xid, tcon,
|
||||
open_file,
|
||||
size, false);
|
||||
cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc);
|
||||
} else {
|
||||
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
|
||||
if (open_file) {
|
||||
tcon = tlink_tcon(open_file->tlink);
|
||||
server = tcon->ses->server;
|
||||
rc = server->ops->set_file_size(xid, tcon,
|
||||
open_file,
|
||||
size, false);
|
||||
cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc);
|
||||
cifsFileInfo_put(open_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
goto set_size_out;
|
||||
@@ -3069,20 +3072,15 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
||||
* valid, writeable file handle for it was found or because there was
|
||||
* an error setting it by handle.
|
||||
*/
|
||||
if (server->ops->set_path_size)
|
||||
rc = server->ops->set_path_size(xid, tcon, full_path,
|
||||
attrs->ia_size, cifs_sb, false, dentry);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc);
|
||||
|
||||
if (tlink)
|
||||
cifs_put_tlink(tlink);
|
||||
rc = server->ops->set_path_size(xid, tcon, full_path, size,
|
||||
cifs_sb, false, dentry);
|
||||
cifs_dbg(FYI, "%s: SetEOF by path (setattrs) rc = %d\n", __func__, rc);
|
||||
cifs_put_tlink(tlink);
|
||||
|
||||
set_size_out:
|
||||
if (rc == 0) {
|
||||
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
|
||||
cifs_setsize(inode, attrs->ia_size);
|
||||
netfs_resize_file(&cifsInode->netfs, size, true);
|
||||
cifs_setsize(inode, size);
|
||||
/*
|
||||
* i_blocks is not related to (i_size / i_blksize), but instead
|
||||
* 512 byte (2**9) size is required for calculating num blocks.
|
||||
@@ -3090,15 +3088,7 @@ set_size_out:
|
||||
* this is best estimate we have for blocks allocated for a file
|
||||
* Number of blocks must be rounded up so size 1 is not 0 blocks
|
||||
*/
|
||||
inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
|
||||
|
||||
/*
|
||||
* The man page of truncate says if the size changed,
|
||||
* then the st_ctime and st_mtime fields for the file
|
||||
* are updated.
|
||||
*/
|
||||
attrs->ia_ctime = attrs->ia_mtime = current_time(inode);
|
||||
attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME;
|
||||
inode->i_blocks = (512 - 1 + size) >> 9;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -3118,7 +3108,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct cifs_unix_set_info_args *args = NULL;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
|
||||
cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n",
|
||||
direntry, attrs->ia_valid);
|
||||
@@ -3132,6 +3122,9 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (attrs->ia_valid & ATTR_FILE)
|
||||
open_file = attrs->ia_file->private_data;
|
||||
|
||||
full_path = build_path_from_dentry(direntry, page);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
@@ -3159,9 +3152,16 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
rc = 0;
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
|
||||
rc = cifs_file_set_size(xid, direntry, full_path,
|
||||
open_file, attrs->ia_size);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
/*
|
||||
* Avoid setting timestamps on the server for ftruncate(2) to
|
||||
* prevent it from disabling automatic timestamp updates as per
|
||||
* MS-FSA 2.1.4.17.
|
||||
*/
|
||||
attrs->ia_valid &= ~(ATTR_CTIME | ATTR_MTIME);
|
||||
}
|
||||
|
||||
/* skip mode change if it's just for clearing setuid/setgid */
|
||||
@@ -3206,14 +3206,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
args->ctime = NO_CHANGE_64;
|
||||
|
||||
args->device = 0;
|
||||
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
|
||||
if (open_file) {
|
||||
u16 nfid = open_file->fid.netfid;
|
||||
u32 npid = open_file->pid;
|
||||
rc = -EINVAL;
|
||||
if (open_file && (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE)) {
|
||||
pTcon = tlink_tcon(open_file->tlink);
|
||||
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
|
||||
cifsFileInfo_put(open_file);
|
||||
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args,
|
||||
open_file->fid.netfid,
|
||||
open_file->pid);
|
||||
} else {
|
||||
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
|
||||
if (open_file) {
|
||||
pTcon = tlink_tcon(open_file->tlink);
|
||||
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args,
|
||||
open_file->fid.netfid,
|
||||
open_file->pid);
|
||||
cifsFileInfo_put(open_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
rc = PTR_ERR(tlink);
|
||||
@@ -3221,8 +3231,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
||||
}
|
||||
pTcon = tlink_tcon(tlink);
|
||||
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb));
|
||||
cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb));
|
||||
cifs_put_tlink(tlink);
|
||||
}
|
||||
|
||||
@@ -3264,8 +3274,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
struct inode *inode = d_inode(direntry);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||
struct cifsFileInfo *wfile;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifsFileInfo *cfile = NULL;
|
||||
const char *full_path;
|
||||
void *page = alloc_dentry_path();
|
||||
int rc = -EACCES;
|
||||
@@ -3285,6 +3294,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
if (rc < 0)
|
||||
goto cifs_setattr_exit;
|
||||
|
||||
if (attrs->ia_valid & ATTR_FILE)
|
||||
cfile = attrs->ia_file->private_data;
|
||||
|
||||
full_path = build_path_from_dentry(direntry, page);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
@@ -3311,25 +3323,23 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
|
||||
rc = 0;
|
||||
|
||||
if ((attrs->ia_valid & ATTR_MTIME) &&
|
||||
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
||||
rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
|
||||
if (!rc) {
|
||||
tcon = tlink_tcon(wfile->tlink);
|
||||
rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
|
||||
cifsFileInfo_put(wfile);
|
||||
if (rc)
|
||||
goto cifs_setattr_exit;
|
||||
} else if (rc != -EBADF)
|
||||
if (attrs->ia_valid & ATTR_MTIME) {
|
||||
rc = cifs_file_flush(xid, inode, cfile);
|
||||
if (rc)
|
||||
goto cifs_setattr_exit;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
|
||||
rc = cifs_file_set_size(xid, direntry, full_path,
|
||||
cfile, attrs->ia_size);
|
||||
if (rc != 0)
|
||||
goto cifs_setattr_exit;
|
||||
/*
|
||||
* Avoid setting timestamps on the server for ftruncate(2) to
|
||||
* prevent it from disabling automatic timestamp updates as per
|
||||
* MS-FSA 2.1.4.17.
|
||||
*/
|
||||
attrs->ia_valid &= ~(ATTR_CTIME | ATTR_MTIME);
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_UID)
|
||||
@@ -3459,6 +3469,13 @@ cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
/*
|
||||
* Avoid setting [cm]time with O_TRUNC to prevent the server from
|
||||
* disabling automatic timestamp updates as specified in
|
||||
* MS-FSA 2.1.4.17.
|
||||
*/
|
||||
if (attrs->ia_valid & ATTR_OPEN)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
|
||||
@@ -651,14 +651,72 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
/*
|
||||
* For non-symlink WSL reparse points it is required to fetch
|
||||
* EA $LXMOD which contains in its S_DT part the mandatory file type.
|
||||
*/
|
||||
if (!rc && data->reparse_point) {
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
u32 next = 0;
|
||||
|
||||
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
|
||||
do {
|
||||
ea = (void *)((u8 *)ea + next);
|
||||
next = le32_to_cpu(ea->next_entry_offset);
|
||||
} while (next);
|
||||
if (le16_to_cpu(ea->ea_value_length)) {
|
||||
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
|
||||
ea->ea_name_length + 1 +
|
||||
le16_to_cpu(ea->ea_value_length), 4));
|
||||
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
|
||||
}
|
||||
|
||||
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
|
||||
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
|
||||
SMB2_WSL_XATTR_MODE_SIZE, cifs_sb);
|
||||
if (rc == SMB2_WSL_XATTR_MODE_SIZE) {
|
||||
ea->next_entry_offset = cpu_to_le32(0);
|
||||
ea->flags = 0;
|
||||
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
|
||||
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_MODE_SIZE);
|
||||
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
|
||||
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_MODE_SIZE, 4);
|
||||
rc = 0;
|
||||
} else if (rc >= 0) {
|
||||
/* It is an error if EA $LXMOD has wrong size. */
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* In all other cases ignore error if fetching
|
||||
* of EA $LXMOD failed. It is needed only for
|
||||
* non-symlink WSL reparse points and wsl_to_fattr()
|
||||
* handle the case when EA is missing.
|
||||
*/
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For WSL CHR and BLK reparse points it is required to fetch
|
||||
* EA $LXDEV which contains major and minor device numbers.
|
||||
*/
|
||||
if (!rc && data->reparse_point) {
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
u32 next = 0;
|
||||
|
||||
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
|
||||
do {
|
||||
ea = (void *)((u8 *)ea + next);
|
||||
next = le32_to_cpu(ea->next_entry_offset);
|
||||
} while (next);
|
||||
if (le16_to_cpu(ea->ea_value_length)) {
|
||||
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
|
||||
ea->ea_name_length + 1 +
|
||||
le16_to_cpu(ea->ea_value_length), 4));
|
||||
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
|
||||
}
|
||||
|
||||
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV,
|
||||
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
|
||||
SMB2_WSL_XATTR_DEV_SIZE, cifs_sb);
|
||||
@@ -668,8 +726,8 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
|
||||
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
|
||||
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
|
||||
data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_DEV_SIZE;
|
||||
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_MODE_SIZE, 4);
|
||||
rc = 0;
|
||||
} else if (rc >= 0) {
|
||||
/* It is an error if EA $LXDEV has wrong size. */
|
||||
@@ -818,6 +876,11 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
|
||||
info.Attributes = cpu_to_le32(dosattrs);
|
||||
rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
|
||||
cifs_sb);
|
||||
if (rc == -EOPNOTSUPP || rc == -EINVAL)
|
||||
rc = SMBSetInformation(xid, tcon, full_path,
|
||||
info.Attributes,
|
||||
0 /* do not change write time */,
|
||||
cifs_sb->local_nls, cifs_sb);
|
||||
if (rc == 0)
|
||||
cifsInode->cifsAttrs = dosattrs;
|
||||
}
|
||||
@@ -974,7 +1037,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
|
||||
.tcon = tcon,
|
||||
.cifs_sb = cifs_sb,
|
||||
.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
|
||||
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
|
||||
.create_options = cifs_create_options(cifs_sb, 0),
|
||||
.disposition = FILE_OPEN,
|
||||
.path = full_path,
|
||||
.fid = &fid,
|
||||
|
||||
@@ -676,7 +676,7 @@ finished:
|
||||
idata->fi.EndOfFile = create_rsp->EndofFile;
|
||||
if (le32_to_cpu(idata->fi.NumberOfLinks) == 0)
|
||||
idata->fi.NumberOfLinks = cpu_to_le32(1); /* dummy value */
|
||||
idata->fi.DeletePending = 0;
|
||||
idata->fi.DeletePending = 0; /* successful open = not delete pending */
|
||||
idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
|
||||
|
||||
/* smb2_parse_contexts() fills idata->fi.IndexNumber */
|
||||
@@ -1382,31 +1382,33 @@ int
|
||||
smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
FILE_BASIC_INFO *buf, const unsigned int xid)
|
||||
{
|
||||
struct cifs_open_parms oparms;
|
||||
struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifsFileInfo *cfile = NULL;
|
||||
struct cifs_open_parms oparms;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
|
||||
int rc;
|
||||
|
||||
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
||||
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
|
||||
(buf->Attributes == 0))
|
||||
return 0; /* would be a no op, no sense sending this */
|
||||
int rc = 0;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
||||
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0)) {
|
||||
if (buf->Attributes == 0)
|
||||
goto out; /* would be a no op, no sense sending this */
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
}
|
||||
|
||||
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
|
||||
FILE_OPEN, 0, ACL_NO_MODE);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb,
|
||||
full_path, &oparms, &in_iov,
|
||||
&(int){SMB2_OP_SET_INFO}, 1,
|
||||
cfile, NULL, NULL, NULL);
|
||||
out:
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1803,140 +1803,226 @@ free_vars:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* calc_chunk_count - calculates the number chunks to be filled in the Chunks[]
|
||||
* array of struct copychunk_ioctl
|
||||
*
|
||||
* @tcon: destination file tcon
|
||||
* @bytes_left: how many bytes are left to copy
|
||||
*
|
||||
* Return: maximum number of chunks with which Chunks[] can be filled.
|
||||
*/
|
||||
static inline u32
|
||||
calc_chunk_count(struct cifs_tcon *tcon, u64 bytes_left)
|
||||
{
|
||||
u32 max_chunks = READ_ONCE(tcon->max_chunks);
|
||||
u32 max_bytes_copy = READ_ONCE(tcon->max_bytes_copy);
|
||||
u32 max_bytes_chunk = READ_ONCE(tcon->max_bytes_chunk);
|
||||
u64 need;
|
||||
u32 allowed;
|
||||
|
||||
if (!max_bytes_chunk || !max_bytes_copy || !max_chunks)
|
||||
return 0;
|
||||
|
||||
/* chunks needed for the remaining bytes */
|
||||
need = DIV_ROUND_UP_ULL(bytes_left, max_bytes_chunk);
|
||||
/* chunks allowed per cc request */
|
||||
allowed = DIV_ROUND_UP(max_bytes_copy, max_bytes_chunk);
|
||||
|
||||
return (u32)umin(need, umin(max_chunks, allowed));
|
||||
}
|
||||
|
||||
/**
|
||||
* smb2_copychunk_range - server-side copy of data range
|
||||
*
|
||||
* @xid: transaction id
|
||||
* @src_file: source file
|
||||
* @dst_file: destination file
|
||||
* @src_off: source file byte offset
|
||||
* @len: number of bytes to copy
|
||||
* @dst_off: destination file byte offset
|
||||
*
|
||||
* Obtains a resume key for @src_file and issues FSCTL_SRV_COPYCHUNK_WRITE
|
||||
* IOCTLs, splitting the request into chunks limited by tcon->max_*.
|
||||
*
|
||||
* Return: @len on success; negative errno on failure.
|
||||
*/
|
||||
static ssize_t
|
||||
smb2_copychunk_range(const unsigned int xid,
|
||||
struct cifsFileInfo *srcfile,
|
||||
struct cifsFileInfo *trgtfile, u64 src_off,
|
||||
u64 len, u64 dest_off)
|
||||
struct cifsFileInfo *src_file,
|
||||
struct cifsFileInfo *dst_file,
|
||||
u64 src_off,
|
||||
u64 len,
|
||||
u64 dst_off)
|
||||
{
|
||||
int rc;
|
||||
unsigned int ret_data_len;
|
||||
struct copychunk_ioctl *pcchunk;
|
||||
struct copychunk_ioctl_rsp *retbuf = NULL;
|
||||
int rc = 0;
|
||||
unsigned int ret_data_len = 0;
|
||||
struct copychunk_ioctl *cc_req = NULL;
|
||||
struct copychunk_ioctl_rsp *cc_rsp = NULL;
|
||||
struct cifs_tcon *tcon;
|
||||
int chunks_copied = 0;
|
||||
bool chunk_sizes_updated = false;
|
||||
ssize_t bytes_written, total_bytes_written = 0;
|
||||
struct copychunk *chunk;
|
||||
u32 chunks, chunk_count, chunk_bytes;
|
||||
u32 copy_bytes, copy_bytes_left;
|
||||
u32 chunks_written, bytes_written;
|
||||
u64 total_bytes_left = len;
|
||||
u64 src_off_prev, dst_off_prev;
|
||||
u32 retries = 0;
|
||||
|
||||
pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
|
||||
if (pcchunk == NULL)
|
||||
return -ENOMEM;
|
||||
tcon = tlink_tcon(dst_file->tlink);
|
||||
|
||||
cifs_dbg(FYI, "%s: about to call request res key\n", __func__);
|
||||
/* Request a key from the server to identify the source of the copy */
|
||||
rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
|
||||
srcfile->fid.persistent_fid,
|
||||
srcfile->fid.volatile_fid, pcchunk);
|
||||
trace_smb3_copychunk_enter(xid, src_file->fid.volatile_fid,
|
||||
dst_file->fid.volatile_fid, tcon->tid,
|
||||
tcon->ses->Suid, src_off, dst_off, len);
|
||||
|
||||
/* Note: request_res_key sets res_key null only if rc !=0 */
|
||||
if (rc)
|
||||
goto cchunk_out;
|
||||
|
||||
/* For now array only one chunk long, will make more flexible later */
|
||||
pcchunk->ChunkCount = cpu_to_le32(1);
|
||||
pcchunk->Reserved = 0;
|
||||
pcchunk->Reserved2 = 0;
|
||||
|
||||
tcon = tlink_tcon(trgtfile->tlink);
|
||||
|
||||
trace_smb3_copychunk_enter(xid, srcfile->fid.volatile_fid,
|
||||
trgtfile->fid.volatile_fid, tcon->tid,
|
||||
tcon->ses->Suid, src_off, dest_off, len);
|
||||
|
||||
while (len > 0) {
|
||||
pcchunk->SourceOffset = cpu_to_le64(src_off);
|
||||
pcchunk->TargetOffset = cpu_to_le64(dest_off);
|
||||
pcchunk->Length =
|
||||
cpu_to_le32(min_t(u64, len, tcon->max_bytes_chunk));
|
||||
|
||||
/* Request server copy to target from src identified by key */
|
||||
kfree(retbuf);
|
||||
retbuf = NULL;
|
||||
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
|
||||
trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
|
||||
(char *)pcchunk, sizeof(struct copychunk_ioctl),
|
||||
CIFSMaxBufSize, (char **)&retbuf, &ret_data_len);
|
||||
if (rc == 0) {
|
||||
if (ret_data_len !=
|
||||
sizeof(struct copychunk_ioctl_rsp)) {
|
||||
cifs_tcon_dbg(VFS, "Invalid cchunk response size\n");
|
||||
rc = -EIO;
|
||||
goto cchunk_out;
|
||||
}
|
||||
if (retbuf->TotalBytesWritten == 0) {
|
||||
cifs_dbg(FYI, "no bytes copied\n");
|
||||
rc = -EIO;
|
||||
goto cchunk_out;
|
||||
}
|
||||
/*
|
||||
* Check if server claimed to write more than we asked
|
||||
*/
|
||||
if (le32_to_cpu(retbuf->TotalBytesWritten) >
|
||||
le32_to_cpu(pcchunk->Length)) {
|
||||
cifs_tcon_dbg(VFS, "Invalid copy chunk response\n");
|
||||
rc = -EIO;
|
||||
goto cchunk_out;
|
||||
}
|
||||
if (le32_to_cpu(retbuf->ChunksWritten) != 1) {
|
||||
cifs_tcon_dbg(VFS, "Invalid num chunks written\n");
|
||||
rc = -EIO;
|
||||
goto cchunk_out;
|
||||
}
|
||||
chunks_copied++;
|
||||
|
||||
bytes_written = le32_to_cpu(retbuf->TotalBytesWritten);
|
||||
src_off += bytes_written;
|
||||
dest_off += bytes_written;
|
||||
len -= bytes_written;
|
||||
total_bytes_written += bytes_written;
|
||||
|
||||
cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %zu\n",
|
||||
le32_to_cpu(retbuf->ChunksWritten),
|
||||
le32_to_cpu(retbuf->ChunkBytesWritten),
|
||||
bytes_written);
|
||||
trace_smb3_copychunk_done(xid, srcfile->fid.volatile_fid,
|
||||
trgtfile->fid.volatile_fid, tcon->tid,
|
||||
tcon->ses->Suid, src_off, dest_off, len);
|
||||
} else if (rc == -EINVAL) {
|
||||
if (ret_data_len != sizeof(struct copychunk_ioctl_rsp))
|
||||
goto cchunk_out;
|
||||
|
||||
cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n",
|
||||
le32_to_cpu(retbuf->ChunksWritten),
|
||||
le32_to_cpu(retbuf->ChunkBytesWritten),
|
||||
le32_to_cpu(retbuf->TotalBytesWritten));
|
||||
|
||||
/*
|
||||
* Check if this is the first request using these sizes,
|
||||
* (ie check if copy succeed once with original sizes
|
||||
* and check if the server gave us different sizes after
|
||||
* we already updated max sizes on previous request).
|
||||
* if not then why is the server returning an error now
|
||||
*/
|
||||
if ((chunks_copied != 0) || chunk_sizes_updated)
|
||||
goto cchunk_out;
|
||||
|
||||
/* Check that server is not asking us to grow size */
|
||||
if (le32_to_cpu(retbuf->ChunkBytesWritten) <
|
||||
tcon->max_bytes_chunk)
|
||||
tcon->max_bytes_chunk =
|
||||
le32_to_cpu(retbuf->ChunkBytesWritten);
|
||||
else
|
||||
goto cchunk_out; /* server gave us bogus size */
|
||||
|
||||
/* No need to change MaxChunks since already set to 1 */
|
||||
chunk_sizes_updated = true;
|
||||
} else
|
||||
goto cchunk_out;
|
||||
retry:
|
||||
chunk_count = calc_chunk_count(tcon, total_bytes_left);
|
||||
if (!chunk_count) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cchunk_out:
|
||||
kfree(pcchunk);
|
||||
kfree(retbuf);
|
||||
cc_req = kzalloc(struct_size(cc_req, Chunks, chunk_count), GFP_KERNEL);
|
||||
if (!cc_req) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Request a key from the server to identify the source of the copy */
|
||||
rc = SMB2_request_res_key(xid,
|
||||
tlink_tcon(src_file->tlink),
|
||||
src_file->fid.persistent_fid,
|
||||
src_file->fid.volatile_fid,
|
||||
cc_req);
|
||||
|
||||
/* Note: request_res_key sets res_key null only if rc != 0 */
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
while (total_bytes_left > 0) {
|
||||
|
||||
/* Store previous offsets to allow rewind */
|
||||
src_off_prev = src_off;
|
||||
dst_off_prev = dst_off;
|
||||
|
||||
chunks = 0;
|
||||
copy_bytes = 0;
|
||||
copy_bytes_left = umin(total_bytes_left, tcon->max_bytes_copy);
|
||||
while (copy_bytes_left > 0 && chunks < chunk_count) {
|
||||
chunk = &cc_req->Chunks[chunks++];
|
||||
|
||||
chunk->SourceOffset = cpu_to_le64(src_off);
|
||||
chunk->TargetOffset = cpu_to_le64(dst_off);
|
||||
|
||||
chunk_bytes = umin(copy_bytes_left, tcon->max_bytes_chunk);
|
||||
|
||||
chunk->Length = cpu_to_le32(chunk_bytes);
|
||||
/* Buffer is zeroed, no need to set chunk->Reserved = 0 */
|
||||
|
||||
src_off += chunk_bytes;
|
||||
dst_off += chunk_bytes;
|
||||
|
||||
copy_bytes_left -= chunk_bytes;
|
||||
copy_bytes += chunk_bytes;
|
||||
}
|
||||
|
||||
cc_req->ChunkCount = cpu_to_le32(chunks);
|
||||
/* Buffer is zeroed, no need to set cc_req->Reserved = 0 */
|
||||
|
||||
/* Request server copy to target from src identified by key */
|
||||
kfree(cc_rsp);
|
||||
cc_rsp = NULL;
|
||||
rc = SMB2_ioctl(xid, tcon, dst_file->fid.persistent_fid,
|
||||
dst_file->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
|
||||
(char *)cc_req, struct_size(cc_req, Chunks, chunks),
|
||||
CIFSMaxBufSize, (char **)&cc_rsp, &ret_data_len);
|
||||
|
||||
if (rc && rc != -EINVAL)
|
||||
goto out;
|
||||
|
||||
if (unlikely(ret_data_len != sizeof(*cc_rsp))) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: size %u/%zu\n",
|
||||
ret_data_len, sizeof(*cc_rsp));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bytes_written = le32_to_cpu(cc_rsp->TotalBytesWritten);
|
||||
chunks_written = le32_to_cpu(cc_rsp->ChunksWritten);
|
||||
chunk_bytes = le32_to_cpu(cc_rsp->ChunkBytesWritten);
|
||||
|
||||
if (rc == 0) {
|
||||
/* Check if server claimed to write more than we asked */
|
||||
if (unlikely(!bytes_written || bytes_written > copy_bytes ||
|
||||
!chunks_written || chunks_written > chunks)) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u, chunks written %u/%u\n",
|
||||
bytes_written, copy_bytes, chunks_written, chunks);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Partial write: rewind */
|
||||
if (bytes_written < copy_bytes) {
|
||||
u32 delta = copy_bytes - bytes_written;
|
||||
|
||||
src_off -= delta;
|
||||
dst_off -= delta;
|
||||
}
|
||||
|
||||
total_bytes_left -= bytes_written;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if server is not asking us to reduce size.
|
||||
*
|
||||
* Note: As per MS-SMB2 2.2.32.1, the values returned
|
||||
* in cc_rsp are not strictly lower than what existed
|
||||
* before.
|
||||
*/
|
||||
if (bytes_written < tcon->max_bytes_copy) {
|
||||
cifs_tcon_dbg(FYI, "Copychunk MaxBytesCopy updated: %u -> %u\n",
|
||||
tcon->max_bytes_copy, bytes_written);
|
||||
tcon->max_bytes_copy = bytes_written;
|
||||
}
|
||||
|
||||
if (chunks_written < tcon->max_chunks) {
|
||||
cifs_tcon_dbg(FYI, "Copychunk MaxChunks updated: %u -> %u\n",
|
||||
tcon->max_chunks, chunks_written);
|
||||
tcon->max_chunks = chunks_written;
|
||||
}
|
||||
|
||||
if (chunk_bytes < tcon->max_bytes_chunk) {
|
||||
cifs_tcon_dbg(FYI, "Copychunk MaxBytesChunk updated: %u -> %u\n",
|
||||
tcon->max_bytes_chunk, chunk_bytes);
|
||||
tcon->max_bytes_chunk = chunk_bytes;
|
||||
}
|
||||
|
||||
/* reset to last offsets */
|
||||
if (retries++ < 2) {
|
||||
src_off = src_off_prev;
|
||||
dst_off = dst_off_prev;
|
||||
kfree(cc_req);
|
||||
cc_req = NULL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(cc_req);
|
||||
kfree(cc_rsp);
|
||||
if (rc) {
|
||||
trace_smb3_copychunk_err(xid, src_file->fid.volatile_fid,
|
||||
dst_file->fid.volatile_fid, tcon->tid,
|
||||
tcon->ses->Suid, src_off, dst_off, len, rc);
|
||||
return rc;
|
||||
else
|
||||
return total_bytes_written;
|
||||
} else {
|
||||
trace_smb3_copychunk_done(xid, src_file->fid.volatile_fid,
|
||||
dst_file->fid.volatile_fid, tcon->tid,
|
||||
tcon->ses->Suid, src_off, dst_off, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3281,7 +3367,6 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
ses->Suid, offset, len);
|
||||
|
||||
inode_lock(inode);
|
||||
filemap_invalidate_lock(inode->i_mapping);
|
||||
|
||||
i_size = i_size_read(inode);
|
||||
@@ -3299,6 +3384,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
* first, otherwise the data may be inconsistent with the server.
|
||||
*/
|
||||
truncate_pagecache_range(inode, offset, offset + len - 1);
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
|
||||
/* if file not oplocked can't be sure whether asking to extend size */
|
||||
rc = -EOPNOTSUPP;
|
||||
@@ -3327,7 +3413,6 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
zero_range_exit:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
inode_unlock(inode);
|
||||
free_xid(xid);
|
||||
if (rc)
|
||||
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
@@ -3351,7 +3436,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
inode_lock(inode);
|
||||
/* Need to make file sparse, if not already, before freeing range. */
|
||||
/* Consider adding equivalent for compressed since it could also work */
|
||||
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
|
||||
@@ -3365,6 +3449,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
* caches first, otherwise the data may be inconsistent with the server.
|
||||
*/
|
||||
truncate_pagecache_range(inode, offset, offset + len - 1);
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
|
||||
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
|
||||
|
||||
@@ -3399,7 +3484,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
unlock:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
@@ -3663,8 +3747,6 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
old_eof = i_size_read(inode);
|
||||
if ((off >= old_eof) ||
|
||||
off + len >= old_eof) {
|
||||
@@ -3679,6 +3761,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
truncate_pagecache_range(inode, off, old_eof);
|
||||
ictx->zero_point = old_eof;
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
|
||||
rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
|
||||
old_eof - off - len, off);
|
||||
@@ -3699,8 +3782,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
|
||||
fscache_resize_cookie(cifs_inode_cookie(inode), new_eof);
|
||||
out_2:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
out:
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
@@ -3717,8 +3799,6 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
old_eof = i_size_read(inode);
|
||||
if (off >= old_eof) {
|
||||
rc = -EINVAL;
|
||||
@@ -3733,6 +3813,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
|
||||
if (rc < 0)
|
||||
goto out_2;
|
||||
truncate_pagecache_range(inode, off, old_eof);
|
||||
netfs_wait_for_outstanding_io(inode);
|
||||
|
||||
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, cfile->pid, new_eof);
|
||||
@@ -3755,8 +3836,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
|
||||
rc = 0;
|
||||
out_2:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
out:
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
@@ -4650,7 +4730,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
unsigned int pad_len;
|
||||
struct cifs_io_subrequest *rdata = mid->callback_data;
|
||||
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
||||
int length;
|
||||
size_t copied;
|
||||
bool use_rdma_mr = false;
|
||||
|
||||
if (shdr->Command != SMB2_READ) {
|
||||
@@ -4763,10 +4843,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
} else if (buf_len >= data_offset + data_len) {
|
||||
/* read response payload is in buf */
|
||||
WARN_ONCE(buffer, "read data can be either in buf or in buffer");
|
||||
length = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
|
||||
if (length < 0)
|
||||
return length;
|
||||
rdata->got_bytes = data_len;
|
||||
copied = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
|
||||
if (copied == 0)
|
||||
return -EIO;
|
||||
rdata->got_bytes = copied;
|
||||
} else {
|
||||
/* read response payload cannot be in both buf and pages */
|
||||
WARN_ONCE(1, "buf can not contain only a part of read data");
|
||||
|
||||
@@ -3277,7 +3277,7 @@ replay_again:
|
||||
buf->EndOfFile = rsp->EndofFile;
|
||||
buf->Attributes = rsp->FileAttributes;
|
||||
buf->NumberOfLinks = cpu_to_le32(1);
|
||||
buf->DeletePending = 0;
|
||||
buf->DeletePending = 0; /* successful open = not delete pending */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -201,16 +201,20 @@ struct resume_key_req {
|
||||
char Context[]; /* ignored, Windows sets to 4 bytes of zero */
|
||||
} __packed;
|
||||
|
||||
|
||||
struct copychunk {
|
||||
__le64 SourceOffset;
|
||||
__le64 TargetOffset;
|
||||
__le32 Length;
|
||||
__le32 Reserved;
|
||||
} __packed;
|
||||
|
||||
/* this goes in the ioctl buffer when doing a copychunk request */
|
||||
struct copychunk_ioctl {
|
||||
char SourceKey[COPY_CHUNK_RES_KEY_SIZE];
|
||||
__le32 ChunkCount; /* we are only sending 1 */
|
||||
__le32 ChunkCount;
|
||||
__le32 Reserved;
|
||||
/* array will only be one chunk long for us */
|
||||
__le64 SourceOffset;
|
||||
__le64 TargetOffset;
|
||||
__le32 Length; /* how many bytes to copy */
|
||||
__u32 Reserved2;
|
||||
struct copychunk Chunks[];
|
||||
} __packed;
|
||||
|
||||
struct copychunk_ioctl_rsp {
|
||||
|
||||
@@ -240,11 +240,6 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
|
||||
return NULL;
|
||||
}
|
||||
tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid);
|
||||
if (!tcon) {
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
cifs_put_smb_ses(ses);
|
||||
return NULL;
|
||||
}
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
/* tcon already has a ref to ses, so we don't need ses anymore */
|
||||
cifs_put_smb_ses(ses);
|
||||
|
||||
@@ -266,7 +266,7 @@ DEFINE_EVENT(smb3_copy_range_err_class, smb3_##name, \
|
||||
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len, rc))
|
||||
|
||||
DEFINE_SMB3_COPY_RANGE_ERR_EVENT(clone_err);
|
||||
/* TODO: Add SMB3_COPY_RANGE_ERR_EVENT(copychunk_err) */
|
||||
DEFINE_SMB3_COPY_RANGE_ERR_EVENT(copychunk_err);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_copy_range_done_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
|
||||
Reference in New Issue
Block a user