Skip to content

Commit

Permalink
cifs: Cut over to using netfslib
Browse files Browse the repository at this point in the history
Make the cifs filesystem use netfslib to handle reading and writing on
behalf of cifs.  The changes include:

 (1) Various read_iter/write_iter type functions are turned into wrappers
     around netfslib API functions or are pointed directly at those
     functions:

	cifs_file_direct{,_nobrl}_ops switch to use
	netfs_unbuffered_read_iter and netfs_unbuffered_write_iter.

Large pieces of code that will be removed are #if'd out and will be removed
in subsequent patches.

[?] Why does cifs mark the page dirty in the destination buffer of a DIO
    read?  Should that happen automatically?  Does netfs need to do that?

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Shyam Prasad N <nspmangalore@gmail.com>
cc: Rohith Surabattula <rohiths.msft@gmail.com>
cc: Jeff Layton <jlayton@kernel.org>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
cc: linux-mm@kvack.org
  • Loading branch information
David Howells committed May 1, 2024
1 parent 69c3c02 commit 3ee1a1f
Show file tree
Hide file tree
Showing 14 changed files with 361 additions and 180 deletions.
7 changes: 6 additions & 1 deletion fs/netfs/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,13 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq)
unsigned int i;
size_t transferred = 0;

for (i = 0; i < rreq->direct_bv_count; i++)
for (i = 0; i < rreq->direct_bv_count; i++) {
flush_dcache_page(rreq->direct_bv[i].bv_page);
// TODO: cifs marks pages in the destination buffer
// dirty under some circumstances after a read. Do we
// need to do that too?
set_page_dirty(rreq->direct_bv[i].bv_page);
}

list_for_each_entry(subreq, &rreq->subrequests, rreq_link) {
if (subreq->error || subreq->transferred == 0)
Expand Down
8 changes: 4 additions & 4 deletions fs/smb/client/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,8 +1522,8 @@ const struct file_operations cifs_file_strict_ops = {
};

const struct file_operations cifs_file_direct_ops = {
.read_iter = cifs_direct_readv,
.write_iter = cifs_direct_writev,
.read_iter = netfs_unbuffered_read_iter,
.write_iter = netfs_file_write_iter,
.open = cifs_open,
.release = cifs_close,
.lock = cifs_lock,
Expand Down Expand Up @@ -1578,8 +1578,8 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
};

const struct file_operations cifs_file_direct_nobrl_ops = {
.read_iter = cifs_direct_readv,
.write_iter = cifs_direct_writev,
.read_iter = netfs_unbuffered_read_iter,
.write_iter = netfs_file_write_iter,
.open = cifs_open,
.release = cifs_close,
.fsync = cifs_fsync,
Expand Down
7 changes: 0 additions & 7 deletions fs/smb/client/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,7 @@ extern const struct file_operations cifs_file_strict_nobrl_ops;
extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to);
extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from);
ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter);
Expand All @@ -112,9 +108,6 @@ extern int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, struct dir_context *ctx);
extern void cifs_pages_written_back(struct inode *inode, loff_t start, unsigned int len);
extern void cifs_pages_write_failed(struct inode *inode, loff_t start, unsigned int len);
extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned int len);

/* Functions related to dir entries */
extern const struct dentry_operations cifs_dentry_ops;
Expand Down
5 changes: 3 additions & 2 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ struct smb_version_operations {
/* async read from the server */
int (*async_readv)(struct cifs_io_subrequest *);
/* async write to the server */
int (*async_writev)(struct cifs_io_subrequest *);
void (*async_writev)(struct cifs_io_subrequest *);
/* sync read from the server */
int (*sync_read)(const unsigned int, struct cifs_fid *,
struct cifs_io_parms *, unsigned int *, char **,
Expand Down Expand Up @@ -1516,7 +1516,7 @@ struct cifs_io_subrequest {
#endif
struct cifs_credits credits;

// TODO: Remove following elements
#if 0 // TODO: Remove following elements
struct list_head list;
struct completion done;
struct work_struct work;
Expand All @@ -1526,6 +1526,7 @@ struct cifs_io_subrequest {
enum writeback_sync_modes sync_mode;
bool uncached;
struct bio_vec *bv;
#endif
};

/*
Expand Down
8 changes: 7 additions & 1 deletion fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 eof,
bool from_readdir);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written);
void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result,
bool was_async);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
int flags,
Expand Down Expand Up @@ -599,6 +601,7 @@ void __cifs_put_smb_ses(struct cifs_ses *ses);
extern struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);

#if 0 // TODO Remove
void cifs_readdata_release(struct cifs_io_subrequest *rdata);
static inline void cifs_get_readdata(struct cifs_io_subrequest *rdata)
{
Expand All @@ -609,11 +612,13 @@ static inline void cifs_put_readdata(struct cifs_io_subrequest *rdata)
if (refcount_dec_and_test(&rdata->subreq.ref))
cifs_readdata_release(rdata);
}
#endif
int cifs_async_readv(struct cifs_io_subrequest *rdata);
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);

int cifs_async_writev(struct cifs_io_subrequest *wdata);
void cifs_async_writev(struct cifs_io_subrequest *wdata);
void cifs_writev_complete(struct work_struct *work);
#if 0 // TODO Remove
struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete);
void cifs_writedata_release(struct cifs_io_subrequest *rdata);
static inline void cifs_get_writedata(struct cifs_io_subrequest *wdata)
Expand All @@ -625,6 +630,7 @@ static inline void cifs_put_writedata(struct cifs_io_subrequest *wdata)
if (refcount_dec_and_test(&wdata->subreq.ref))
cifs_writedata_release(wdata);
}
#endif
int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
Expand Down
54 changes: 32 additions & 22 deletions fs/smb/client/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,7 @@ static void
cifs_readv_callback(struct mid_q_entry *mid)
{
struct cifs_io_subrequest *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2,
Expand Down Expand Up @@ -1306,7 +1306,13 @@ cifs_readv_callback(struct mid_q_entry *mid)
rdata->result = -EIO;
}

queue_work(cifsiod_wq, &rdata->work);
if (rdata->result == 0 || rdata->result == -EAGAIN)
iov_iter_advance(&rdata->subreq.io_iter, rdata->got_bytes);
rdata->credits.value = 0;
netfs_subreq_terminated(&rdata->subreq,
(rdata->result == 0 || rdata->result == -EAGAIN) ?
rdata->got_bytes : rdata->result,
false);
release_mid(mid);
add_credits(server, &credits, 0);
}
Expand All @@ -1318,7 +1324,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
int rc;
READ_REQ *smb = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2 };

Expand All @@ -1343,7 +1349,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));

smb->AndXCommand = 0xFF; /* none */
smb->Fid = rdata->cfile->fid.netfid;
smb->Fid = rdata->req->cfile->fid.netfid;
smb->OffsetLow = cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF);
if (wct == 12)
smb->OffsetHigh = cpu_to_le32(rdata->subreq.start >> 32);
Expand Down Expand Up @@ -1613,15 +1619,16 @@ static void
cifs_writev_callback(struct mid_q_entry *mid)
{
struct cifs_io_subrequest *wdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
unsigned int written;
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
struct cifs_credits credits = { .value = 1, .instance = 0 };
ssize_t result;
size_t written;

switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
if (wdata->result != 0)
result = cifs_check_receive(mid, tcon->ses->server, 0);
if (result != 0)
break;

written = le16_to_cpu(smb->CountHigh);
Expand All @@ -1637,32 +1644,33 @@ cifs_writev_callback(struct mid_q_entry *mid)
written &= 0xFFFF;

if (written < wdata->subreq.len)
wdata->result = -ENOSPC;
result = -ENOSPC;
else
wdata->subreq.len = written;
result = written;
break;
case MID_REQUEST_SUBMITTED:
case MID_RETRY_NEEDED:
wdata->result = -EAGAIN;
result = -EAGAIN;
break;
default:
wdata->result = -EIO;
result = -EIO;
break;
}

queue_work(cifsiod_wq, &wdata->work);
wdata->credits.value = 0;
cifs_write_subrequest_terminated(wdata, result, true);
release_mid(mid);
add_credits(tcon->ses->server, &credits, 0);
}

/* cifs_async_writev - send an async write, and set up mid to handle result */
int
void
cifs_async_writev(struct cifs_io_subrequest *wdata)
{
int rc = -EACCES;
WRITE_REQ *smb = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
struct kvec iov[2];
struct smb_rqst rqst = { };

Expand All @@ -1672,7 +1680,8 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
wct = 12;
if (wdata->subreq.start >> 32 > 0) {
/* can not handle big offset for old srv */
return -EIO;
rc = -EIO;
goto out;
}
}

Expand All @@ -1684,7 +1693,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));

smb->AndXCommand = 0xFF; /* none */
smb->Fid = wdata->cfile->fid.netfid;
smb->Fid = wdata->req->cfile->fid.netfid;
smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
if (wct == 14)
smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
Expand Down Expand Up @@ -1724,18 +1733,19 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
iov[1].iov_len += 4; /* pad bigger by four bytes */
}

cifs_get_writedata(wdata);
rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
cifs_writev_callback, NULL, wdata, 0, NULL);

/* Can't touch wdata if rc == 0 */
if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
else
cifs_put_writedata(wdata);

async_writev_out:
cifs_small_buf_release(smb);
return rc;
out:
if (rc) {
add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
cifs_write_subrequest_terminated(wdata, rc, false);
}
}

int
Expand Down
Loading

0 comments on commit 3ee1a1f

Please sign in to comment.