Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
c48722c6
Commit
c48722c6
authored
Apr 11, 2015
by
Al Viro
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '9p-iov_iter' into for-next
parents
34d0640e
dcdbd7b2
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
355 additions
and
627 deletions
+355
-627
fs/9p/v9fs_vfs.h
fs/9p/v9fs_vfs.h
+0
-4
fs/9p/vfs_addr.c
fs/9p/vfs_addr.c
+37
-43
fs/9p/vfs_dir.c
fs/9p/vfs_dir.c
+11
-4
fs/9p/vfs_file.c
fs/9p/vfs_file.c
+66
-260
fs/9p/xattr.c
fs/9p/xattr.c
+25
-55
include/net/9p/client.h
include/net/9p/client.h
+4
-4
include/net/9p/transport.h
include/net/9p/transport.h
+1
-1
net/9p/client.c
net/9p/client.c
+123
-139
net/9p/protocol.c
net/9p/protocol.c
+8
-16
net/9p/trans_common.c
net/9p/trans_common.c
+1
-41
net/9p/trans_common.h
net/9p/trans_common.h
+0
-2
net/9p/trans_virtio.c
net/9p/trans_virtio.c
+79
-58
No files found.
fs/9p/v9fs_vfs.h
View file @
c48722c6
...
...
@@ -68,14 +68,10 @@ int v9fs_file_open(struct inode *inode, struct file *file);
void
v9fs_inode2stat
(
struct
inode
*
inode
,
struct
p9_wstat
*
stat
);
int
v9fs_uflags2omode
(
int
uflags
,
int
extended
);
ssize_t
v9fs_file_readn
(
struct
file
*
,
char
*
,
char
__user
*
,
u32
,
u64
);
ssize_t
v9fs_fid_readn
(
struct
p9_fid
*
,
char
*
,
char
__user
*
,
u32
,
u64
);
void
v9fs_blank_wstat
(
struct
p9_wstat
*
wstat
);
int
v9fs_vfs_setattr_dotl
(
struct
dentry
*
,
struct
iattr
*
);
int
v9fs_file_fsync_dotl
(
struct
file
*
filp
,
loff_t
start
,
loff_t
end
,
int
datasync
);
ssize_t
v9fs_file_write_internal
(
struct
inode
*
,
struct
p9_fid
*
,
const
char
__user
*
,
size_t
,
loff_t
*
,
int
);
int
v9fs_refresh_inode
(
struct
p9_fid
*
fid
,
struct
inode
*
inode
);
int
v9fs_refresh_inode_dotl
(
struct
p9_fid
*
fid
,
struct
inode
*
inode
);
static
inline
void
v9fs_invalidate_inode_attr
(
struct
inode
*
inode
)
...
...
fs/9p/vfs_addr.c
View file @
c48722c6
...
...
@@ -51,12 +51,11 @@
*/
static
int
v9fs_fid_readpage
(
struct
p9_fid
*
fid
,
struct
page
*
page
)
{
int
retval
;
loff_t
offset
;
char
*
buffer
;
struct
inode
*
inode
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
bio_vec
bvec
=
{.
bv_page
=
page
,
.
bv_len
=
PAGE_SIZE
}
;
struct
iov_iter
to
;
int
retval
,
err
;
inode
=
page
->
mapping
->
host
;
p9_debug
(
P9_DEBUG_VFS
,
"
\n
"
);
BUG_ON
(
!
PageLocked
(
page
));
...
...
@@ -65,16 +64,16 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
if
(
retval
==
0
)
return
retval
;
buffer
=
kmap
(
page
);
offset
=
page_offset
(
page
);
iov_iter_bvec
(
&
to
,
ITER_BVEC
|
READ
,
&
bvec
,
1
,
PAGE_SIZE
);
retval
=
v9fs_fid_readn
(
fid
,
buffer
,
NULL
,
PAGE_CACHE_SIZE
,
offset
);
if
(
retval
<
0
)
{
retval
=
p9_client_read
(
fid
,
page_offset
(
page
),
&
to
,
&
err
);
if
(
err
)
{
v9fs_uncache_page
(
inode
,
page
);
retval
=
err
;
goto
done
;
}
memset
(
buffer
+
retval
,
0
,
PAGE_CACH
E_SIZE
-
retval
);
zero_user
(
page
,
retval
,
PAG
E_SIZE
-
retval
);
flush_dcache_page
(
page
);
SetPageUptodate
(
page
);
...
...
@@ -82,7 +81,6 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
retval
=
0
;
done:
kunmap
(
page
);
unlock_page
(
page
);
return
retval
;
}
...
...
@@ -161,41 +159,32 @@ static void v9fs_invalidate_page(struct page *page, unsigned int offset,
static
int
v9fs_vfs_writepage_locked
(
struct
page
*
page
)
{
char
*
buffer
;
int
retval
,
len
;
loff_t
offset
,
size
;
mm_segment_t
old_fs
;
struct
v9fs_inode
*
v9inode
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
v9fs_inode
*
v9inode
=
V9FS_I
(
inode
);
loff_t
size
=
i_size_read
(
inode
);
struct
iov_iter
from
;
struct
bio_vec
bvec
;
int
err
,
len
;
v9inode
=
V9FS_I
(
inode
);
size
=
i_size_read
(
inode
);
if
(
page
->
index
==
size
>>
PAGE_CACHE_SHIFT
)
len
=
size
&
~
PAGE_CACHE_MASK
;
else
len
=
PAGE_CACHE_SIZE
;
set_page_writeback
(
page
)
;
b
uffer
=
kmap
(
page
)
;
offset
=
page_offset
(
page
);
bvec
.
bv_page
=
page
;
bvec
.
bv_offset
=
0
;
b
vec
.
bv_len
=
len
;
iov_iter_bvec
(
&
from
,
ITER_BVEC
|
WRITE
,
&
bvec
,
1
,
len
);
old_fs
=
get_fs
();
set_fs
(
get_ds
());
/* We should have writeback_fid always set */
BUG_ON
(
!
v9inode
->
writeback_fid
);
retval
=
v9fs_file_write_internal
(
inode
,
v9inode
->
writeback_fid
,
(
__force
const
char
__user
*
)
buffer
,
len
,
&
offset
,
0
);
if
(
retval
>
0
)
retval
=
0
;
set_page_writeback
(
page
);
p9_client_write
(
v9inode
->
writeback_fid
,
page_offset
(
page
),
&
from
,
&
err
);
set_fs
(
old_fs
);
kunmap
(
page
);
end_page_writeback
(
page
);
return
retval
;
return
err
;
}
static
int
v9fs_vfs_writepage
(
struct
page
*
page
,
struct
writeback_control
*
wbc
)
...
...
@@ -261,16 +250,21 @@ static int v9fs_launder_page(struct page *page)
static
ssize_t
v9fs_direct_IO
(
int
rw
,
struct
kiocb
*
iocb
,
struct
iov_iter
*
iter
,
loff_t
pos
)
{
/*
* FIXME
* Now that we do caching with cache mode enabled, We need
* to support direct IO
*/
p9_debug
(
P9_DEBUG_VFS
,
"v9fs_direct_IO: v9fs_direct_IO (%pD) off/no(%lld/%lu) EINVAL
\n
"
,
iocb
->
ki_filp
,
(
long
long
)
pos
,
iter
->
nr_segs
);
return
-
EINVAL
;
struct
file
*
file
=
iocb
->
ki_filp
;
ssize_t
n
;
int
err
=
0
;
if
(
rw
&
WRITE
)
{
n
=
p9_client_write
(
file
->
private_data
,
pos
,
iter
,
&
err
);
if
(
n
)
{
struct
inode
*
inode
=
file_inode
(
file
);
loff_t
i_size
=
i_size_read
(
inode
);
if
(
pos
+
n
>
i_size
)
inode_add_bytes
(
inode
,
pos
+
n
-
i_size
);
}
}
else
{
n
=
p9_client_read
(
file
->
private_data
,
pos
,
iter
,
&
err
);
}
return
n
?
n
:
err
;
}
static
int
v9fs_write_begin
(
struct
file
*
filp
,
struct
address_space
*
mapping
,
...
...
fs/9p/vfs_dir.c
View file @
c48722c6
...
...
@@ -33,6 +33,7 @@
#include <linux/inet.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/uio.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
...
...
@@ -115,6 +116,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
int
buflen
;
int
reclen
=
0
;
struct
p9_rdir
*
rdir
;
struct
kvec
kvec
;
p9_debug
(
P9_DEBUG_VFS
,
"name %pD
\n
"
,
file
);
fid
=
file
->
private_data
;
...
...
@@ -124,16 +126,21 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
rdir
=
v9fs_alloc_rdir_buf
(
file
,
buflen
);
if
(
!
rdir
)
return
-
ENOMEM
;
kvec
.
iov_base
=
rdir
->
buf
;
kvec
.
iov_len
=
buflen
;
while
(
1
)
{
if
(
rdir
->
tail
==
rdir
->
head
)
{
err
=
v9fs_file_readn
(
file
,
rdir
->
buf
,
NULL
,
buflen
,
ctx
->
pos
);
if
(
err
<=
0
)
struct
iov_iter
to
;
int
n
;
iov_iter_kvec
(
&
to
,
READ
|
ITER_KVEC
,
&
kvec
,
1
,
buflen
);
n
=
p9_client_read
(
file
->
private_data
,
ctx
->
pos
,
&
to
,
&
err
);
if
(
err
)
return
err
;
rdir
->
head
=
0
;
rdir
->
tail
=
err
;
rdir
->
tail
=
n
;
}
while
(
rdir
->
head
<
rdir
->
tail
)
{
p9stat_init
(
&
st
);
...
...
fs/9p/vfs_file.c
View file @
c48722c6
This diff is collapsed.
Click to expand it.
fs/9p/xattr.c
View file @
c48722c6
...
...
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/uio.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
...
...
@@ -25,50 +26,34 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
void
*
buffer
,
size_t
buffer_size
)
{
ssize_t
retval
;
int
msize
,
read_count
;
u64
offset
=
0
,
attr_size
;
u64
attr_size
;
struct
p9_fid
*
attr_fid
;
struct
kvec
kvec
=
{.
iov_base
=
buffer
,
.
iov_len
=
buffer_size
};
struct
iov_iter
to
;
int
err
;
iov_iter_kvec
(
&
to
,
READ
|
ITER_KVEC
,
&
kvec
,
1
,
buffer_size
);
attr_fid
=
p9_client_xattrwalk
(
fid
,
name
,
&
attr_size
);
if
(
IS_ERR
(
attr_fid
))
{
retval
=
PTR_ERR
(
attr_fid
);
p9_debug
(
P9_DEBUG_VFS
,
"p9_client_attrwalk failed %zd
\n
"
,
retval
);
attr_fid
=
NULL
;
goto
error
;
}
if
(
!
buffer_size
)
{
/* request to get the attr_size */
retval
=
attr_size
;
goto
error
;
return
retval
;
}
if
(
attr_size
>
buffer_size
)
{
retval
=
-
ERANGE
;
goto
error
;
}
msize
=
attr_fid
->
clnt
->
msize
;
while
(
attr_size
)
{
if
(
attr_size
>
(
msize
-
P9_IOHDRSZ
))
read_count
=
msize
-
P9_IOHDRSZ
;
if
(
!
buffer_size
)
/* request to get the attr_size */
retval
=
attr_size
;
else
read_count
=
attr_size
;
read_count
=
p9_client_read
(
attr_fid
,
((
char
*
)
buffer
)
+
offset
,
NULL
,
offset
,
read_count
);
if
(
read_count
<
0
)
{
/* error in xattr read */
retval
=
read_count
;
goto
error
;
}
offset
+=
read_count
;
attr_size
-=
read_count
;
retval
=
-
ERANGE
;
}
else
{
iov_iter_truncate
(
&
to
,
attr_size
);
retval
=
p9_client_read
(
attr_fid
,
0
,
&
to
,
&
err
);
if
(
err
)
retval
=
err
;
}
/* Total read xattr bytes */
retval
=
offset
;
error:
if
(
attr_fid
)
p9_client_clunk
(
attr_fid
);
p9_client_clunk
(
attr_fid
);
return
retval
;
}
...
...
@@ -120,8 +105,11 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
int
v9fs_fid_xattr_set
(
struct
p9_fid
*
fid
,
const
char
*
name
,
const
void
*
value
,
size_t
value_len
,
int
flags
)
{
u64
offset
=
0
;
int
retval
,
msize
,
write_count
;
struct
kvec
kvec
=
{.
iov_base
=
(
void
*
)
value
,
.
iov_len
=
value_len
};
struct
iov_iter
from
;
int
retval
;
iov_iter_kvec
(
&
from
,
WRITE
|
ITER_KVEC
,
&
kvec
,
1
,
value_len
);
p9_debug
(
P9_DEBUG_VFS
,
"name = %s value_len = %zu flags = %d
\n
"
,
name
,
value_len
,
flags
);
...
...
@@ -135,29 +123,11 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
* On success fid points to xattr
*/
retval
=
p9_client_xattrcreate
(
fid
,
name
,
value_len
,
flags
);
if
(
retval
<
0
)
{
if
(
retval
<
0
)
p9_debug
(
P9_DEBUG_VFS
,
"p9_client_xattrcreate failed %d
\n
"
,
retval
);
goto
err
;
}
msize
=
fid
->
clnt
->
msize
;
while
(
value_len
)
{
if
(
value_len
>
(
msize
-
P9_IOHDRSZ
))
write_count
=
msize
-
P9_IOHDRSZ
;
else
write_count
=
value_len
;
write_count
=
p9_client_write
(
fid
,
((
char
*
)
value
)
+
offset
,
NULL
,
offset
,
write_count
);
if
(
write_count
<
0
)
{
/* error in xattr write */
retval
=
write_count
;
goto
err
;
}
offset
+=
write_count
;
value_len
-=
write_count
;
}
retval
=
0
;
err:
else
p9_client_write
(
fid
,
0
,
&
from
,
&
retval
);
p9_client_clunk
(
fid
);
return
retval
;
}
...
...
include/net/9p/client.h
View file @
c48722c6
...
...
@@ -211,6 +211,8 @@ struct p9_dirent {
char
d_name
[
256
];
};
struct
iov_iter
;
int
p9_client_statfs
(
struct
p9_fid
*
fid
,
struct
p9_rstatfs
*
sb
);
int
p9_client_rename
(
struct
p9_fid
*
fid
,
struct
p9_fid
*
newdirfid
,
const
char
*
name
);
...
...
@@ -236,10 +238,8 @@ int p9_client_clunk(struct p9_fid *fid);
int
p9_client_fsync
(
struct
p9_fid
*
fid
,
int
datasync
);
int
p9_client_remove
(
struct
p9_fid
*
fid
);
int
p9_client_unlinkat
(
struct
p9_fid
*
dfid
,
const
char
*
name
,
int
flags
);
int
p9_client_read
(
struct
p9_fid
*
fid
,
char
*
data
,
char
__user
*
udata
,
u64
offset
,
u32
count
);
int
p9_client_write
(
struct
p9_fid
*
fid
,
char
*
data
,
const
char
__user
*
udata
,
u64
offset
,
u32
count
);
int
p9_client_read
(
struct
p9_fid
*
fid
,
u64
offset
,
struct
iov_iter
*
to
,
int
*
err
);
int
p9_client_write
(
struct
p9_fid
*
fid
,
u64
offset
,
struct
iov_iter
*
from
,
int
*
err
);
int
p9_client_readdir
(
struct
p9_fid
*
fid
,
char
*
data
,
u32
count
,
u64
offset
);
int
p9dirent_read
(
struct
p9_client
*
clnt
,
char
*
buf
,
int
len
,
struct
p9_dirent
*
dirent
);
...
...
include/net/9p/transport.h
View file @
c48722c6
...
...
@@ -61,7 +61,7 @@ struct p9_trans_module {
int
(
*
cancel
)
(
struct
p9_client
*
,
struct
p9_req_t
*
req
);
int
(
*
cancelled
)(
struct
p9_client
*
,
struct
p9_req_t
*
req
);
int
(
*
zc_request
)(
struct
p9_client
*
,
struct
p9_req_t
*
,
char
*
,
char
*
,
int
,
int
,
int
,
int
);
struct
iov_iter
*
,
struct
iov_iter
*
,
int
,
int
,
int
);
};
void
v9fs_register_trans
(
struct
p9_trans_module
*
m
);
...
...
net/9p/client.c
View file @
c48722c6
This diff is collapsed.
Click to expand it.
net/9p/protocol.c
View file @
c48722c6
...
...
@@ -33,6 +33,7 @@
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include <linux/uio.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
#include "protocol.h"
...
...
@@ -69,10 +70,11 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
}
static
size_t
pdu_write_u
(
struct
p9_fcall
*
pdu
,
const
char
__user
*
udata
,
size_t
size
)
pdu_write_u
(
struct
p9_fcall
*
pdu
,
struct
iov_iter
*
from
,
size_t
size
)
{
size_t
len
=
min
(
pdu
->
capacity
-
pdu
->
size
,
size
);
if
(
copy_from_user
(
&
pdu
->
sdata
[
pdu
->
size
],
udata
,
len
))
struct
iov_iter
i
=
*
from
;
if
(
copy_from_iter
(
&
pdu
->
sdata
[
pdu
->
size
],
len
,
&
i
)
!=
len
)
len
=
0
;
pdu
->
size
+=
len
;
...
...
@@ -437,23 +439,13 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
stbuf
->
extension
,
stbuf
->
n_uid
,
stbuf
->
n_gid
,
stbuf
->
n_muid
);
}
break
;
case
'D'
:{
uint32_t
count
=
va_arg
(
ap
,
uint32_t
);
const
void
*
data
=
va_arg
(
ap
,
const
void
*
);
errcode
=
p9pdu_writef
(
pdu
,
proto_version
,
"d"
,
count
);
if
(
!
errcode
&&
pdu_write
(
pdu
,
data
,
count
))
errcode
=
-
EFAULT
;
}
break
;
case
'U'
:{
case
'V'
:{
int32_t
count
=
va_arg
(
ap
,
int32_t
);
const
char
__user
*
udata
=
va_arg
(
ap
,
const
void
__us
er
*
);
struct
iov_iter
*
from
=
va_arg
(
ap
,
struct
iov_it
er
*
);
errcode
=
p9pdu_writef
(
pdu
,
proto_version
,
"d"
,
count
);
if
(
!
errcode
&&
pdu_write_u
(
pdu
,
udata
,
count
))
if
(
!
errcode
&&
pdu_write_u
(
pdu
,
from
,
count
))
errcode
=
-
EFAULT
;
}
break
;
...
...
net/9p/trans_common.c
View file @
c48722c6
...
...
@@ -12,12 +12,8 @@
*
*/
#include <linux/
slab
.h>
#include <linux/
mm
.h>
#include <linux/module.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
#include <linux/scatterlist.h>
#include "trans_common.h"
/**
* p9_release_req_pages - Release pages after the transaction.
...
...
@@ -31,39 +27,3 @@ void p9_release_pages(struct page **pages, int nr_pages)
put_page
(
pages
[
i
]);
}
EXPORT_SYMBOL
(
p9_release_pages
);
/**
* p9_nr_pages - Return number of pages needed to accommodate the payload.
*/
int
p9_nr_pages
(
char
*
data
,
int
len
)
{
unsigned
long
start_page
,
end_page
;
start_page
=
(
unsigned
long
)
data
>>
PAGE_SHIFT
;
end_page
=
((
unsigned
long
)
data
+
len
+
PAGE_SIZE
-
1
)
>>
PAGE_SHIFT
;
return
end_page
-
start_page
;
}
EXPORT_SYMBOL
(
p9_nr_pages
);
/**
* payload_gup - Translates user buffer into kernel pages and
* pins them either for read/write through get_user_pages_fast().
* @req: Request to be sent to server.
* @pdata_off: data offset into the first page after translation (gup).
* @pdata_len: Total length of the IO. gup may not return requested # of pages.
* @nr_pages: number of pages to accommodate the payload
* @rw: Indicates if the pages are for read or write.
*/
int
p9_payload_gup
(
char
*
data
,
int
*
nr_pages
,
struct
page
**
pages
,
int
write
)
{
int
nr_mapped_pages
;
nr_mapped_pages
=
get_user_pages_fast
((
unsigned
long
)
data
,
*
nr_pages
,
write
,
pages
);
if
(
nr_mapped_pages
<=
0
)
return
nr_mapped_pages
;
*
nr_pages
=
nr_mapped_pages
;
return
0
;
}
EXPORT_SYMBOL
(
p9_payload_gup
);
net/9p/trans_common.h
View file @
c48722c6
...
...
@@ -13,5 +13,3 @@
*/
void
p9_release_pages
(
struct
page
**
,
int
);
int
p9_payload_gup
(
char
*
,
int
*
,
struct
page
**
,
int
);
int
p9_nr_pages
(
char
*
,
int
);
net/9p/trans_virtio.c
View file @
c48722c6
...
...
@@ -217,15 +217,15 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
* @start: which segment of the sg_list to start at
* @pdata: a list of pages to add into sg.
* @nr_pages: number of pages to pack into the scatter/gather list
* @
data: data to pack into scatter/gather list
* @
offs: amount of data in the beginning of first page _not_ to pack
* @count: amount of data to pack into the scatter/gather list
*/
static
int
pack_sg_list_p
(
struct
scatterlist
*
sg
,
int
start
,
int
limit
,
struct
page
**
pdata
,
int
nr_pages
,
char
*
data
,
int
count
)
struct
page
**
pdata
,
int
nr_pages
,
size_t
offs
,
int
count
)
{
int
i
=
0
,
s
;
int
data_off
;
int
data_off
=
offs
;
int
index
=
start
;
BUG_ON
(
nr_pages
>
(
limit
-
start
));
...
...
@@ -233,16 +233,14 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit,
* if the first page doesn't start at
* page boundary find the offset
*/
data_off
=
offset_in_page
(
data
);
while
(
nr_pages
)
{
s
=
rest_of_page
(
data
)
;
s
=
PAGE_SIZE
-
data_off
;
if
(
s
>
count
)
s
=
count
;
/* Make sure we don't terminate early. */
sg_unmark_end
(
&
sg
[
index
]);
sg_set_page
(
&
sg
[
index
++
],
pdata
[
i
++
],
s
,
data_off
);
data_off
=
0
;
data
+=
s
;
count
-=
s
;
nr_pages
--
;
}
...
...
@@ -314,11 +312,20 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
}
static
int
p9_get_mapped_pages
(
struct
virtio_chan
*
chan
,
struct
page
**
pages
,
char
*
data
,
int
nr_pages
,
int
write
,
int
kern_buf
)
struct
page
***
pages
,
struct
iov_iter
*
data
,
int
count
,
size_t
*
offs
,
int
*
need_drop
)
{
int
nr_pages
;
int
err
;
if
(
!
kern_buf
)
{
if
(
!
iov_iter_count
(
data
))
return
0
;
if
(
!
(
data
->
type
&
ITER_KVEC
))
{
int
n
;
/*
* We allow only p9_max_pages pinned. We wait for the
* Other zc request to finish here
...
...
@@ -329,26 +336,49 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
if
(
err
==
-
ERESTARTSYS
)
return
err
;
}
err
=
p9_payload_gup
(
data
,
&
nr_pages
,
pages
,
write
);
if
(
err
<
0
)
return
err
;
n
=
iov_iter_get_pages_alloc
(
data
,
pages
,
count
,
offs
);
if
(
n
<
0
)
return
n
;
*
need_drop
=
1
;
nr_pages
=
DIV_ROUND_UP
(
n
+
*
offs
,
PAGE_SIZE
);
atomic_add
(
nr_pages
,
&
vp_pinned
);
return
n
;
}
else
{
/* kernel buffer, no need to pin pages */
int
s
,
index
=
0
;
int
count
=
nr_pages
;
while
(
nr_pages
)
{
s
=
rest_of_page
(
data
);
if
(
is_vmalloc_addr
(
data
))
pages
[
index
++
]
=
vmalloc_to_page
(
data
);
int
index
;
size_t
len
;
void
*
p
;
/* we'd already checked that it's non-empty */
while
(
1
)
{
len
=
iov_iter_single_seg_count
(
data
);
if
(
likely
(
len
))
{
p
=
data
->
kvec
->
iov_base
+
data
->
iov_offset
;
break
;
}
iov_iter_advance
(
data
,
0
);
}
if
(
len
>
count
)
len
=
count
;
nr_pages
=
DIV_ROUND_UP
((
unsigned
long
)
p
+
len
,
PAGE_SIZE
)
-
(
unsigned
long
)
p
/
PAGE_SIZE
;
*
pages
=
kmalloc
(
sizeof
(
struct
page
*
)
*
nr_pages
,
GFP_NOFS
);
if
(
!*
pages
)
return
-
ENOMEM
;
*
need_drop
=
0
;
p
-=
(
*
offs
=
(
unsigned
long
)
p
%
PAGE_SIZE
);
for
(
index
=
0
;
index
<
nr_pages
;
index
++
)
{
if
(
is_vmalloc_addr
(
p
))
(
*
pages
)[
index
]
=
vmalloc_to_page
(
p
);
else
pages
[
index
++
]
=
kmap_to_page
(
data
);
data
+=
s
;
nr_pages
--
;
(
*
pages
)[
index
]
=
kmap_to_page
(
p
);
p
+=
PAGE_SIZE
;
}
nr_pages
=
count
;
return
len
;
}
return
nr_pages
;
}
/**
...
...
@@ -364,8 +394,8 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
*/
static
int
p9_virtio_zc_request
(
struct
p9_client
*
client
,
struct
p9_req_t
*
req
,
char
*
uidata
,
char
*
uodata
,
int
inlen
,
int
outlen
,
int
in_hdr_len
,
int
kern_buf
)
struct
iov_iter
*
uidata
,
struct
iov_iter
*
uodata
,
int
inlen
,
int
outlen
,
int
in_hdr_len
)
{
int
in
,
out
,
err
,
out_sgs
,
in_sgs
;
unsigned
long
flags
;
...
...
@@ -373,41 +403,32 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
struct
page
**
in_pages
=
NULL
,
**
out_pages
=
NULL
;
struct
virtio_chan
*
chan
=
client
->
trans
;
struct
scatterlist
*
sgs
[
4
];
size_t
offs
;
int
need_drop
=
0
;
p9_debug
(
P9_DEBUG_TRANS
,
"virtio request
\n
"
);
if
(
uodata
)
{
out_nr_pages
=
p9_nr_pages
(
uodata
,
outlen
);
out_pages
=
kmalloc
(
sizeof
(
struct
page
*
)
*
out_nr_pages
,
GFP_NOFS
);
if
(
!
out_pages
)
{
err
=
-
ENOMEM
;
goto
err_out
;
}
out_nr_pages
=
p9_get_mapped_pages
(
chan
,
out_pages
,
uodata
,
out_nr_pages
,
0
,
kern_buf
);
if
(
out_nr_pages
<
0
)
{
err
=
out_nr_pages
;
kfree
(
out_pages
);
out_pages
=
NULL
;
goto
err_out
;
int
n
=
p9_get_mapped_pages
(
chan
,
&
out_pages
,
uodata
,
outlen
,
&
offs
,
&
need_drop
);
if
(
n
<
0
)
return
n
;
out_nr_pages
=
DIV_ROUND_UP
(
n
+
offs
,
PAGE_SIZE
);
if
(
n
!=
outlen
)
{
__le32
v
=
cpu_to_le32
(
n
);
memcpy
(
&
req
->
tc
->
sdata
[
req
->
tc
->
size
-
4
],
&
v
,
4
);
outlen
=
n
;
}
}
if
(
uidata
)
{
in_nr_pages
=
p9_nr_pages
(
uidata
,
inlen
);
in_pages
=
kmalloc
(
sizeof
(
struct
page
*
)
*
in_nr_pages
,
GFP_NOFS
);
if
(
!
in_pages
)
{
err
=
-
ENOMEM
;
goto
err_out
;
}
in_nr_pages
=
p9_get_mapped_pages
(
chan
,
in_pages
,
uidata
,
in_nr_pages
,
1
,
kern_buf
);
if
(
in_nr_pages
<
0
)
{
err
=
in_nr_pages
;
kfree
(
in_pages
);
in_pages
=
NULL
;
goto
err_out
;
}
else
if
(
uidata
)
{
int
n
=
p9_get_mapped_pages
(
chan
,
&
in_pages
,
uidata
,
inlen
,
&
offs
,
&
need_drop
);
if
(
n
<
0
)
return
n
;
in_nr_pages
=
DIV_ROUND_UP
(
n
+
offs
,
PAGE_SIZE
);
if
(
n
!=
inlen
)
{
__le32
v
=
cpu_to_le32
(
n
);
memcpy
(
&
req
->
tc
->
sdata
[
req
->
tc
->
size
-
4
],
&
v
,
4
);
inlen
=
n
;
}
}
req
->
status
=
REQ_STATUS_SENT
;
...
...
@@ -426,7 +447,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
if
(
out_pages
)
{
sgs
[
out_sgs
++
]
=
chan
->
sg
+
out
;
out
+=
pack_sg_list_p
(
chan
->
sg
,
out
,
VIRTQUEUE_NUM
,
out_pages
,
out_nr_pages
,
uodata
,
outlen
);
out_pages
,
out_nr_pages
,
offs
,
outlen
);
}
/*
...
...
@@ -444,7 +465,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
if
(
in_pages
)
{
sgs
[
out_sgs
+
in_sgs
++
]
=
chan
->
sg
+
out
+
in
;
in
+=
pack_sg_list_p
(
chan
->
sg
,
out
+
in
,
VIRTQUEUE_NUM
,
in_pages
,
in_nr_pages
,
uidata
,
inlen
);
in_pages
,
in_nr_pages
,
offs
,
inlen
);
}
BUG_ON
(
out_sgs
+
in_sgs
>
ARRAY_SIZE
(
sgs
));
...
...
@@ -478,7 +499,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
* Non kernel buffers are pinned, unpin them
*/
err_out:
if
(
!
kern_buf
)
{
if
(
need_drop
)
{
if
(
in_pages
)
{
p9_release_pages
(
in_pages
,
in_nr_pages
);
atomic_sub
(
in_nr_pages
,
&
vp_pinned
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment