--- ./mm/filemap.c 2007-09-12 20:04:16 +0200 +++ ../linux-2.6.22.6/mm/filemap.c 2007-07-09 13:20:04 +0200 @@ -1924,19 +1924,6 @@ int remove_suid(struct dentry *dentry) } EXPORT_SYMBOL(remove_suid); -static inline size_t -filemap_copy_from_kernel(struct page *page, unsigned long offset, - const char *buf, unsigned bytes) -{ - char *kaddr; - - kaddr = kmap(page); - memcpy(kaddr + offset, buf, bytes); - kunmap(page); - - return bytes; -} - size_t __filemap_copy_from_user_iovec_inatomic(char *vaddr, const struct iovec *iov, size_t base, size_t bytes) @@ -2248,175 +2235,6 @@ zero_length_segment: } EXPORT_SYMBOL(generic_file_buffered_write); -static inline void -filemap_set_next_kvec(const struct kvec **iovp, size_t *basep, size_t bytes) -{ - const struct kvec *iov = *iovp; - size_t base = *basep; - - while (bytes) { - int copy = min(bytes, iov->iov_len - base); - - bytes -= copy; - base += copy; - if (iov->iov_len == base) { - iov++; - base = 0; - } - } - *iovp = iov; - *basep = base; -} - -/* - * TODO: - * This largely tries to copy generic_file_aio_write_nolock(), although it - * doesn't have to be nearly as generic. A real cleanup should either - * merge this into generic_file_aio_write_nolock() as well or keep it special - * and remove as much code as possible. - */ -static ssize_t -generic_kernel_file_aio_write_nolock(struct kiocb *iocb, const struct kvec*iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct file *file = iocb->ki_filp; - struct address_space * mapping = file->f_mapping; - const struct address_space_operations *a_ops = mapping->a_ops; - size_t ocount; /* original count */ - size_t count; /* after file limit checks */ - struct inode *inode = mapping->host; - long status = 0; - loff_t pos; - struct page *page; - struct page *cached_page = NULL; - const int isblk = S_ISBLK(inode->i_mode); - ssize_t written; - ssize_t err; - size_t bytes; - struct pagevec lru_pvec; - const struct kvec *cur_iov = iov; /* current kvec */ - size_t iov_base = 0; /* offset in the current kvec */ - unsigned long seg; - char *buf; - - ocount = 0; - for (seg = 0; seg < nr_segs; seg++) { - const struct kvec *iv = &iov[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - ocount += iv->iov_len; - if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) - return -EINVAL; - } - - count = ocount; - pos = *ppos; - pagevec_init(&lru_pvec, 0); - - /* We can write back this queue in page reclaim */ - current->backing_dev_info = mapping->backing_dev_info; - written = 0; - - err = generic_write_checks(file, &pos, &count, isblk); - if (err) - goto out; - - - if (count == 0) - goto out; - - remove_suid(file->f_dentry); - file_update_time(file); - - /* There is no sane reason to use O_DIRECT */ - BUG_ON(file->f_flags & O_DIRECT); - - buf = iov->iov_base; - do { - unsigned long index; - unsigned long offset; - size_t copied; - - offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ - index = pos >> PAGE_CACHE_SHIFT; - bytes = PAGE_CACHE_SIZE - offset; - if (bytes > count) - bytes = count; - - page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); - if (!page) { - status = -ENOMEM; - break; - } - - status = a_ops->prepare_write(file, page, offset, offset+bytes); - if (unlikely(status)) { - loff_t isize = i_size_read(inode); - /* - * prepare_write() may have instantiated a few blocks - * outside i_size. Trim these off again. - */ - unlock_page(page); - page_cache_release(page); - if (pos + bytes > isize) - vmtruncate(inode, isize); - break; - } - - BUG_ON(nr_segs != 1); - copied = filemap_copy_from_kernel(page, offset, buf, bytes); - - flush_dcache_page(page); - status = a_ops->commit_write(file, page, offset, offset+bytes); - if (likely(copied > 0)) { - if (!status) - status = copied; - - if (status >= 0) { - written += status; - count -= status; - pos += status; - buf += status; - if (unlikely(nr_segs > 1)) - filemap_set_next_kvec(&cur_iov, - &iov_base, status); - } - } - if (unlikely(copied != bytes)) - if (status >= 0) - status = -EFAULT; - unlock_page(page); - mark_page_accessed(page); - page_cache_release(page); - if (status < 0) - break; - balance_dirty_pages_ratelimited(mapping); - cond_resched(); - } while (count); - *ppos = pos; - - if (cached_page) - page_cache_release(cached_page); - - /* - * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC - */ - if (status >= 0) { - if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) - status = generic_osync_inode(inode, mapping, - OSYNC_METADATA|OSYNC_DATA); - } - - err = written ? written : status; -out: - pagevec_lru_add(&lru_pvec); - current->backing_dev_info = 0; - return err; -} - static ssize_t __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) @@ -2517,36 +2335,6 @@ out: return written ? written : err; } -static ssize_t -generic_kernel_file_write_nolock(struct file *file, const struct kvec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, file); - ret = generic_kernel_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); - if (ret == -EIOCBQUEUED) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t generic_kernel_file_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_mapping->host; - ssize_t err; - struct kvec local_iov = { .iov_base = (char *) buf, - .iov_len = count }; - - mutex_lock(&inode->i_mutex); - err = generic_kernel_file_write_nolock(file, &local_iov, 1, ppos); - mutex_unlock(&inode->i_mutex); - - return err; -} - - ssize_t generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) {