Here is initial support for size truncation.
It has some problems with unconnected socket closing.
diff --git a/include/net/zerocopy.h b/include/net/zerocopy.h
--- a/include/net/zerocopy.h
+++ b/include/net/zerocopy.h
@@ -152,6 +152,7 @@ struct zsock
u32 zc_seq_first;
void *priv;
unsigned int priv_size;
+ ssize_t written;
};
int sock_zc_setup_seq(struct zsock *zsk, u32 seq);
diff --git a/net/core/zerocopy.c b/net/core/zerocopy.c
--- a/net/core/zerocopy.c
+++ b/net/core/zerocopy.c
@@ -194,6 +194,7 @@ int commit_page(struct zc_page *zp, stru
goto err_out;
}
ClearPageReserved(zp->page);
+ page_cache_release(zp->page);
flush_dcache_page(zp->page);
err = a_ops->commit_write(file, zp->page, zp->page_offset,
zp->page_offset+zp->used);
unlock_page(zp->page);
@@ -235,7 +236,7 @@ int prepare_page(struct zc_page *zp, str
bytes = PAGE_CACHE_SIZE - page_offset;
if (bytes > count)
bytes = count;
-
+
if (down_interruptible(&mapping->host->i_sem)) {
err = -EBUSY;
goto err_out;
@@ -245,15 +246,17 @@ int prepare_page(struct zc_page *zp, str
err = -ENOMEM;
goto err_out_exit;
}
+ page_cache_get(zp->page);
err = a_ops->prepare_write(file, zp->page, page_offset,
page_offset+bytes);
if (unlikely(err)) {
+ page_cache_release(zp->page);
unlock_page(zp->page);
page_cache_release(zp->page);
goto err_out_exit;
}
SetPageReserved(zp->page);
-
+
zc_clean_page(zp);
zp->page_offset = page_offset;
@@ -272,6 +275,20 @@ err_out:
return err;
}
+static int zc_set_size(struct zsock *zsk)
+{
+ struct address_space *mapping = zsk->zc_file->f_mapping;
+ struct inode *inode = mapping->host;
+ int err;
+
+ down(&inode->i_sem);
+ down_write(&inode->i_alloc_sem);
+ err = vmtruncate(inode, zsk->written);
+ up_write(&inode->i_alloc_sem);
+ up(&inode->i_sem);
+
+ return err;
+}
void sk_zc_fini(struct zsock *zsk)
{
@@ -284,7 +301,7 @@ void sk_zc_fini(struct zsock *zsk)
write_lock_irqsave(&zsk->zc_lock, flags);
zc_page_num = zsk->zc_page_num;
zc_pages = zsk->zc_pages;
-
+
zsk->zc_pages = NULL;
zsk->zc_page_num = 0;
zsk->zc_page_index = 0;
@@ -301,7 +318,6 @@ void sk_zc_fini(struct zsock *zsk)
if (zc_page_num) {
struct address_space *mapping = zsk->zc_file->f_mapping;
- loff_t size = 0;
int i;
if (sk)
@@ -318,10 +334,10 @@ void sk_zc_fini(struct zsock *zsk)
* due to above locked changes.
*/
- for (i=0; i<zc_page_num; ++i) {
+ for (i=zc_page_num-1; i>=0; --i) {
+ //for (i=0; i<zc_page_num; ++i) {
struct zc_page *zp = &zc_pages[i];
- size += zp->used;
commit_page(zp, zsk->zc_file, mapping);
zc_clean_page(zp);
}
@@ -331,10 +347,8 @@ void sk_zc_fini(struct zsock *zsk)
zsk->zc_cached_page = NULL;
}
- pagevec_lru_add(&zsk->zc_lru_pvec);
+ zc_set_size(zsk);
- if (!size)
- zsk->zc_file->f_pos = size;
zsk->zc_file->f_mode &= ~FMODE_ZEROCOPY;
fput(zsk->zc_file);
zsk->zc_file = NULL;
diff --git a/net/socket.c b/net/socket.c
--- a/net/socket.c
+++ b/net/socket.c
@@ -1212,7 +1212,6 @@ int tcp_udp_v4_sock_zc_init(struct socke
}
pagevec_init(&zsk->zc_lru_pvec, 0);
- file->f_pos = 0;
err = 0;
for (i=0; i<pnum_max; ++i) {
@@ -1275,7 +1274,6 @@ static ssize_t sock_sendfile(struct file
struct socket *sock;
struct sock *sk;
int err = 0;
- size_t written = 0;
struct file *file = target;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
@@ -1304,6 +1302,7 @@ static ssize_t sock_sendfile(struct file
}
zsk_get(zsk);
+ zsk->written = 0;
while (count) {
struct zc_page *zp;
@@ -1319,7 +1318,7 @@ static ssize_t sock_sendfile(struct file
goto err_out_release_all_pages;
count -= zp->used;
- written += zp->used;
+ zsk->written += zp->used;
err = prepare_page(zp, zsk, file, mapping,
&zsk->zc_pos, count, &zsk->zc_lru_pvec);
}
@@ -1334,8 +1333,10 @@ static ssize_t sock_sendfile(struct file
}
}
- *ppos = written;
- err = written;
+ pagevec_lru_add(&zsk->zc_lru_pvec);
+
+ *ppos = zsk->written;
+ err = zsk->written;
err_out_release_all_pages:
--
Evgeniy Polyakov
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html