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