From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Hellwig Subject: [PATCH] Rework sendfile code to use a file operation (3rd resend) Date: Sun, 28 Jul 2002 14:29:17 +0200 Sender: linux-fsdevel-owner@vger.kernel.org Message-ID: <20020728142917.A22824@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: linux-kerne@vger.kernel.org, linux-fsdevel@vger.kernel.org Return-path: To: Linus Torvalds Content-Disposition: inline List-Id: linux-fsdevel.vger.kernel.org The current sendfile code only checks for the presence of a readpage method on the filesystem from which it sends but assumes it has the same locking semantics as generic_file_read. For all those filesystems that use the pagecache but use a different read implementation (or a wrapper around generic_file_read that does additional locking in most cases) this is broken and allows for races, depending on the locking performed. Filesystems for which this is an issue are tmpfs, smbfs, xfs and maybe others. This patch adds a new sendfile member to the file operations vector and splits the current sendfile implementations in a higher level part (now in fs/read_write.c) and generic_file_sendfile that can be used for all filesystems using generic_file_read. I've also updated all filesystems using generic_file_read to use generic_file_sendfile aswell. Once this is in I will add proper sendfile support to XFS. I guess the maintainers will fixup tmpfs and smbfs (at least tmpfs is very easy). BK patch below: -- You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== ChangeSet@1.477, 2002-07-27 17:24:07+02:00, hch@sb.bsdonline.org VFS: implement sendfile file operation Currently the sendfile syscalls hardcode assumptions about the implementation of the read file operations implementation. Although it checks for the presence of a readpage address-space operation filesystems in Linux are free to implement read differently from the generic version (generic_file_read). Many filesystems such as tmpfs, smbfs or xfs chose to implement it differently and need additional locking, revalidation or checks. fs/adfs/file.c | 1 fs/affs/file.c | 1 fs/bfs/file.c | 9 +-- fs/block_dev.c | 1 fs/ext2/file.c | 1 fs/ext3/file.c | 1 fs/freevxfs/vxfs_inode.c | 1 fs/hpfs/inode.c | 1 fs/jffs/inode-v23.c | 15 ++--- fs/jffs2/file.c | 1 fs/jfs/file.c | 1 fs/minix/file.c | 1 fs/ntfs/file.c | 1 fs/qnx4/file.c | 1 fs/ramfs/inode.c | 1 fs/read_write.c | 111 +++++++++++++++++++++++++++++++++++++++ fs/reiserfs/file.c | 1 fs/sysv/file.c | 1 fs/udf/file.c | 1 fs/ufs/file.c | 1 include/linux/fs.h | 2 kernel/ksyms.c | 1 mm/filemap.c | 132 ++++------------------------------------------- 23 files changed, 158 insertions, 129 deletions diff -Nru a/fs/adfs/file.c b/fs/adfs/file.c --- a/fs/adfs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/adfs/file.c Sun Jul 28 15:25:12 2002 @@ -36,6 +36,7 @@ mmap: generic_file_mmap, fsync: file_fsync, write: generic_file_write, + sendfile: generic_file_sendfile, }; struct inode_operations adfs_file_inode_operations = { diff -Nru a/fs/affs/file.c b/fs/affs/file.c --- a/fs/affs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/affs/file.c Sun Jul 28 15:25:12 2002 @@ -50,6 +50,7 @@ open: affs_file_open, release: affs_file_release, fsync: file_fsync, + sendfile: generic_file_sendfile, }; struct inode_operations affs_file_inode_operations = { diff -Nru a/fs/bfs/file.c b/fs/bfs/file.c --- a/fs/bfs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/bfs/file.c Sun Jul 28 15:25:12 2002 @@ -18,10 +18,11 @@ #endif struct file_operations bfs_file_operations = { - llseek: generic_file_llseek, - read: generic_file_read, - write: generic_file_write, - mmap: generic_file_mmap, + llseek: generic_file_llseek, + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, + sendfile: generic_file_sendfile, }; static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb) diff -Nru a/fs/block_dev.c b/fs/block_dev.c --- a/fs/block_dev.c Sun Jul 28 15:25:12 2002 +++ b/fs/block_dev.c Sun Jul 28 15:25:12 2002 @@ -774,6 +774,7 @@ mmap: generic_file_mmap, fsync: block_fsync, ioctl: blkdev_ioctl, + sendfile: generic_file_sendfile, }; int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c --- a/fs/ext2/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/ext2/file.c Sun Jul 28 15:25:12 2002 @@ -46,6 +46,7 @@ open: generic_file_open, release: ext2_release_file, fsync: ext2_sync_file, + sendfile: generic_file_sendfile, }; struct inode_operations ext2_file_inode_operations = { diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c --- a/fs/ext3/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/ext3/file.c Sun Jul 28 15:25:12 2002 @@ -84,6 +84,7 @@ open: ext3_open_file, /* BKL not held. Don't need */ release: ext3_release_file, /* BKL not held. Don't need */ fsync: ext3_sync_file, /* BKL held */ + sendfile: generic_file_sendfile, /* BKL not held. Don't need */ }; struct inode_operations ext3_file_inode_operations = { diff -Nru a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c --- a/fs/freevxfs/vxfs_inode.c Sun Jul 28 15:25:12 2002 +++ b/fs/freevxfs/vxfs_inode.c Sun Jul 28 15:25:12 2002 @@ -53,6 +53,7 @@ .llseek = generic_file_llseek, .read = generic_file_read, .mmap = generic_file_mmap, + .sendfile = generic_file_sendfile, }; diff -Nru a/fs/hpfs/inode.c b/fs/hpfs/inode.c --- a/fs/hpfs/inode.c Sun Jul 28 15:25:12 2002 +++ b/fs/hpfs/inode.c Sun Jul 28 15:25:12 2002 @@ -21,6 +21,7 @@ open: hpfs_open, release: hpfs_file_release, fsync: hpfs_file_fsync, + sendfile: generic_file_sendfile, }; static struct inode_operations hpfs_file_iops = diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c --- a/fs/jffs/inode-v23.c Sun Jul 28 15:25:12 2002 +++ b/fs/jffs/inode-v23.c Sun Jul 28 15:25:12 2002 @@ -1631,13 +1631,14 @@ static struct file_operations jffs_file_operations = { - open: generic_file_open, - llseek: generic_file_llseek, - read: generic_file_read, - write: generic_file_write, - ioctl: jffs_ioctl, - mmap: generic_file_mmap, - fsync: jffs_fsync, + open: generic_file_open, + llseek: generic_file_llseek, + read: generic_file_read, + write: generic_file_write, + ioctl: jffs_ioctl, + mmap: generic_file_mmap, + fsync: jffs_fsync, + sendfile: generic_file_sendfile, }; diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c --- a/fs/jffs2/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/jffs2/file.c Sun Jul 28 15:25:12 2002 @@ -82,6 +82,7 @@ ioctl: jffs2_ioctl, mmap: generic_file_mmap, fsync: jffs2_fsync + sendfile: generic_file_sendfile, }; /* jffs2_file_inode_operations */ diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c --- a/fs/jfs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/jfs/file.c Sun Jul 28 15:25:12 2002 @@ -98,5 +98,6 @@ .write = generic_file_write, .read = generic_file_read, .mmap = generic_file_mmap, + .sendfile = generic_file_sendfile, .fsync = jfs_fsync, }; diff -Nru a/fs/minix/file.c b/fs/minix/file.c --- a/fs/minix/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/minix/file.c Sun Jul 28 15:25:12 2002 @@ -21,6 +21,7 @@ write: generic_file_write, mmap: generic_file_mmap, fsync: minix_sync_file, + sendfile: generic_file_sendfile, }; struct inode_operations minix_file_inode_operations = { diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c --- a/fs/ntfs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/ntfs/file.c Sun Jul 28 15:25:12 2002 @@ -52,6 +52,7 @@ llseek: generic_file_llseek, /* Seek inside file. */ read: generic_file_read, /* Read from file. */ mmap: generic_file_mmap, /* Mmap file. */ + sendfile: generic_file_sendfile, /* Zero-copy data send */ open: ntfs_file_open, /* Open file. */ }; diff -Nru a/fs/qnx4/file.c b/fs/qnx4/file.c --- a/fs/qnx4/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/qnx4/file.c Sun Jul 28 15:25:12 2002 @@ -33,6 +33,7 @@ #ifdef CONFIG_QNX4FS_RW fsync: qnx4_sync_file, #endif + sendfile: generic_file_sendfile, }; struct inode_operations qnx4_file_inode_operations = diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c --- a/fs/ramfs/inode.c Sun Jul 28 15:25:12 2002 +++ b/fs/ramfs/inode.c Sun Jul 28 15:25:12 2002 @@ -276,6 +276,7 @@ write: generic_file_write, mmap: generic_file_mmap, fsync: ramfs_sync_file, + sendfile: generic_file_sendfile, }; static struct inode_operations ramfs_dir_inode_operations = { diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Sun Jul 28 15:25:12 2002 +++ b/fs/read_write.c Sun Jul 28 15:25:12 2002 @@ -19,6 +19,7 @@ llseek: generic_file_llseek, read: generic_file_read, mmap: generic_file_mmap, + sendfile: generic_file_sendfile, }; loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) @@ -435,4 +436,114 @@ bad_file: return ret; +} + +static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, + size_t count, loff_t max) +{ + struct file * in_file, * out_file; + struct inode * in_inode, * out_inode; + loff_t pos; + ssize_t retval; + + /* + * Get input file, and verify that it is ok.. + */ + retval = -EBADF; + in_file = fget(in_fd); + if (!in_file) + goto out; + if (!(in_file->f_mode & FMODE_READ)) + goto fput_in; + retval = -EINVAL; + in_inode = in_file->f_dentry->d_inode; + if (!in_inode) + goto fput_in; + if (!in_file->f_op || !in_file->f_op->sendfile) + goto fput_in; + retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count); + if (retval) + goto fput_in; + + /* + * Get output file, and verify that it is ok.. + */ + retval = -EBADF; + out_file = fget(out_fd); + if (!out_file) + goto fput_in; + if (!(out_file->f_mode & FMODE_WRITE)) + goto fput_out; + retval = -EINVAL; + if (!out_file->f_op || !out_file->f_op->sendpage) + goto fput_out; + out_inode = out_file->f_dentry->d_inode; + retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count); + if (retval) + goto fput_out; + + if (!ppos) + ppos = &in_file->f_pos; + + if (!max) + max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); + + pos = *ppos; + retval = -EINVAL; + if (unlikely(pos < 0)) + goto fput_out; + if (unlikely(pos + count > max)) { + retval = -EOVERFLOW; + if (pos >= max) + goto fput_out; + count = max - pos; + } + + retval = in_file->f_op->sendfile(out_file, in_file, ppos, count); + + if (*ppos > max) + retval = -EOVERFLOW; + +fput_out: + fput(out_file); +fput_in: + fput(in_file); +out: + return retval; +} + +asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) +{ + loff_t pos; + off_t off; + ssize_t ret; + + if (offset) { + if (unlikely(get_user(off, offset))) + return -EFAULT; + pos = off; + ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); + if (unlikely(put_user(pos, offset))) + return -EFAULT; + return ret; + } + + return do_sendfile(out_fd, in_fd, NULL, count, MAX_NON_LFS); +} + +asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count) +{ + loff_t pos; + ssize_t ret; + + if (offset) { + if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) + return -EFAULT; + ret = do_sendfile(out_fd, in_fd, &pos, count, 0); + if (unlikely(put_user(pos, offset))) + return -EFAULT; + return ret; + } + + return do_sendfile(out_fd, in_fd, NULL, count, 0); } diff -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c --- a/fs/reiserfs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/reiserfs/file.c Sun Jul 28 15:25:12 2002 @@ -147,6 +147,7 @@ mmap: generic_file_mmap, release: reiserfs_file_release, fsync: reiserfs_sync_file, + sendfile: generic_file_sendfile, }; diff -Nru a/fs/sysv/file.c b/fs/sysv/file.c --- a/fs/sysv/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/sysv/file.c Sun Jul 28 15:25:12 2002 @@ -25,6 +25,7 @@ write: generic_file_write, mmap: generic_file_mmap, fsync: sysv_sync_file, + sendfile: generic_file_sendfile, }; struct inode_operations sysv_file_inode_operations = { diff -Nru a/fs/udf/file.c b/fs/udf/file.c --- a/fs/udf/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/udf/file.c Sun Jul 28 15:25:12 2002 @@ -365,6 +365,7 @@ write: udf_file_write, release: udf_release_file, fsync: udf_fsync_file, + sendfile: generic_file_sendfile, }; struct inode_operations udf_file_inode_operations = { diff -Nru a/fs/ufs/file.c b/fs/ufs/file.c --- a/fs/ufs/file.c Sun Jul 28 15:25:12 2002 +++ b/fs/ufs/file.c Sun Jul 28 15:25:12 2002 @@ -47,6 +47,7 @@ write: generic_file_write, mmap: generic_file_mmap, open: generic_file_open, + sendfile: generic_file_sendfile, }; struct inode_operations ufs_file_inode_operations = { diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Sun Jul 28 15:25:12 2002 +++ b/include/linux/fs.h Sun Jul 28 15:25:12 2002 @@ -757,6 +757,7 @@ int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); + ssize_t (*sendfile) (struct file *, struct file *, loff_t *, size_t); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; @@ -1234,6 +1235,7 @@ extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); +extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf, loff_t offset, size_t count); diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Sun Jul 28 15:25:12 2002 +++ b/kernel/ksyms.c Sun Jul 28 15:25:12 2002 @@ -218,6 +218,7 @@ EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_file_read); +EXPORT_SYMBOL(generic_file_sendfile); EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(generic_file_write); EXPORT_SYMBOL(generic_file_mmap); diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Sun Jul 28 15:25:12 2002 +++ b/mm/filemap.c Sun Jul 28 15:25:12 2002 @@ -1119,127 +1119,23 @@ return written; } -static ssize_t common_sendfile(int out_fd, int in_fd, loff_t *offset, size_t count, loff_t max) +ssize_t generic_file_sendfile(struct file *in_file, struct file *out_file, + loff_t *ppos, size_t count) { - ssize_t retval; - struct file * in_file, * out_file; - struct inode * in_inode, * out_inode; + read_descriptor_t desc; - /* - * Get input file, and verify that it is ok.. - */ - retval = -EBADF; - in_file = fget(in_fd); - if (!in_file) - goto out; - if (!(in_file->f_mode & FMODE_READ)) - goto fput_in; - retval = -EINVAL; - in_inode = in_file->f_dentry->d_inode; - if (!in_inode) - goto fput_in; - if (!in_inode->i_mapping->a_ops->readpage) - goto fput_in; - retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count); - if (retval) - goto fput_in; + if (!count) + return 0; - retval = security_ops->file_permission (in_file, MAY_READ); - if (retval) - goto fput_in; - - /* - * Get output file, and verify that it is ok.. - */ - retval = -EBADF; - out_file = fget(out_fd); - if (!out_file) - goto fput_in; - if (!(out_file->f_mode & FMODE_WRITE)) - goto fput_out; - retval = -EINVAL; - if (!out_file->f_op || !out_file->f_op->sendpage) - goto fput_out; - out_inode = out_file->f_dentry->d_inode; - retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count); - if (retval) - goto fput_out; - - retval = security_ops->file_permission (out_file, MAY_WRITE); - if (retval) - goto fput_out; - - retval = 0; - if (count) { - read_descriptor_t desc; - loff_t pos; - - if (!offset) - offset = &in_file->f_pos; - - pos = *offset; - retval = -EINVAL; - if (unlikely(pos < 0)) - goto fput_out; - if (unlikely(pos + count > max)) { - retval = -EOVERFLOW; - if (pos >= max) - goto fput_out; - count = max - pos; - } - - desc.written = 0; - desc.count = count; - desc.buf = (char *) out_file; - desc.error = 0; - do_generic_file_read(in_file, offset, &desc, file_send_actor); - - retval = desc.written; - if (!retval) - retval = desc.error; - pos = *offset; - if (pos > max) - retval = -EOVERFLOW; - } - -fput_out: - fput(out_file); -fput_in: - fput(in_file); -out: - return retval; -} - -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) -{ - loff_t pos, *ppos = NULL; - ssize_t ret; - if (offset) { - off_t off; - if (unlikely(get_user(off, offset))) - return -EFAULT; - pos = off; - ppos = &pos; - } - ret = common_sendfile(out_fd, in_fd, ppos, count, MAX_NON_LFS); - if (offset && put_user(pos, offset)) - ret = -EFAULT; - return ret; -} - -asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count) -{ - loff_t pos, *ppos = NULL; - ssize_t ret; - if (offset) { - if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) - return -EFAULT; - ppos = &pos; - } - ret = common_sendfile(out_fd, in_fd, ppos, count, MAX_LFS_FILESIZE); - if (offset && put_user(pos, offset)) - ret = -EFAULT; - return ret; + desc.written = 0; + desc.count = count; + desc.buf = (char *)out_file; + desc.error = 0; + + do_generic_file_read(in_file, ppos, &desc, file_send_actor); + if (desc.written) + return desc.written; + return desc.error; } static ssize_t =================================================================== This BitKeeper patch contains the following changesets: 1.477 ## Wrapped with gzip_uu ## begin 664 bkpatch8946 M'XL(`+CP0ST``]5<>W/;-A+_6_P4N.E,SDXM&2\2I'/..&F2.T_=II,^[C&= MT8`D:*F62!U)^>(>[[O?`A0E2B0M2FDFXSST`,'%[OX6NXL%J*_0SYE*+P:3 M8&)]A?Z69/G%(/-'?A8F\6P:JU&2WL*%#TD"%\Y3M4C.H7GY<4A'M@47?I!Y M,$'W*LTN!F3$UBWYPT)=##Z\_>O/-Z\^6-;E)?IF(N-;]:/*T>6EE2?IO9R% MV97,)[,D'N6IC+.YRN4H2.;%NFM!,:;PUR:"8=LIB(.Y*`(2$B(Y42&FW'6X MM9#+V3*[RN3-AZPTB(RX$PO0HS^6]V^L`/WR[L<+-)TO9FJNXAQE*@ZCZ4PA\Y(L M5"KS:1)#1_CWS3)-H=/L`>43M>F:/62!G,TR-)%I&"2A0C++EO.%OC%#TD^6 MN;X!"*S',411$AE"J9+ASGC93M<10J]F^219WDXTF1P%$Q7<92A*4D-BD2I@ M)U":I#0$%_(6^`A#N)`-LX4,MJ71PP'?N9K#4#&ZT7:%9`IRITJ!FFLJ,>R% MTRA2*^&C-)D#"3WNK8I5.@V,$6J)3E8-8TU_K.\\!=:_D_'#UHC9,M!RR`SE M\T64G:%L[D<9`F$^PELP2;(='D#B.@>=R,0KJQN@Q MK\"<,U&$4OK*B^#5=X3KAZV&WT('YA.Q*:&XS\+GN89TU> MX!VS0H2"1:X,0CMRJ2>"=E[:*&VX81AS>R\W47;^6P0OTQBFR?">LB9+3%"/ M%5$H`IBTS(X\%0:"M;/426[%%P$).67[\9K&P6P9JM*_GD?9:+++%G%L0,W! MRG/=4$11Z/C*:>>JB]B&*8=3V^VC+%_;]#A4][MZLPNA..[A&#;)UC* M@'>841NE#3?,Q9Z&[O6WNF.H#EPA=6J$A%W`UMX2KJ MTZ`;FCJEG2$)>.1^"M@AL0&$,L'A%?QYY-#(#Z52=D2[Y>_DA3)&G3Z\J(\Y M;67&!7DXA!E/4<'#D`2NE"&U.WEI$-HPPQGG^\T5:,BP0S,N".0Z`)-R)>$N M)\P//>)V<].@5(/)=FQM&0N=5W2RHD/&/3CN<_TR-G.QSI1+'.J`UZ/8+;Q0 MA`$0MQV?.QZ/.IEZA&:-/4?07E:T#*,.*R+DLIP\O.BB._Y-.\Q;D,"A+%#9UN()2F26K##V:`>2]^Y+SR MH$WU<$X\I[!MQD$SGB!"<$:Z)UD+K1I'#G=ZH26C3M-FG&!<1($G?&8[$GNA M=%FW%34HU>("!LWVX6:RZ%(/3'M;Z+Q22$%M)IDC?$A'.L)G*ZFZ=C`6>Z=: MJJ:P9&A3CXT9+2`A`#>M?.$+.Q`^F%'$NHVYE5@M2#%P)'TT]._X(^_`B[L0 M?V&2,<7`+Y(0+#IR_$Z.&I1J1=$;E$007WN1V#) M*O1=W@U6DU1]LMO"63-S-U/3.SE?C.0RRZ?Q:.K/-_SL0$4IL3&Q28&%ZS+0 M,=@R"\%UV*[MVX^E.9WA2X!\>Q4#(8" M%^M4BR>\/A8#ZX#[KDCJ84(*5ZC(Q1`F"*&.DMTNL$&IQ@WWO%ZA=#Z-IQ\[ MV,&.:XO"#\+`<8BG'"<(/=7)39-2C1V;V*Q7L.KV?H0+\%R.X%)BQ51`A:-$ M=[#JM!G&./5,96`[3=/E@2.S0$M.)257@805JS^*80W>F@&:U0+@"HIE$`UT M-0#BR58Q@%P0[]%B`/E6US1"PTJ`:Z&+2.?S8X?X[^I=)D&"2+!P1K6VD*$.CY>85C;6)J'/]@ M?V!I+*9QE,H0LHY.9Z"=K<-A+0BQT>:.`=A^&OB6WJN);TW&8_!U'<"W%[RO MO[U!<9*CB9J%(X3>)/&?]1LM[4UC-:UP\M!AT%4@-?3D/TX'Y[_6/)N,;_Z?;K0 M)""#::?"V0I8N)]3]J0P+9.U)J9U*8^:V+S/Q*YPW$FV]T-Y3*IOW8*=QE>@ M05_&X2B6_@LIV#-:BUVMC^K;-CJG)6*._5;U<9*&,4JE82$$K!Z;I:G=3&U,#H/`T8 MR_IA$\::C,?@R-Q#/&^M"-0/PT/+3^T94H-,E1?1@@M!R^E(GT@,+:ME+4!& MGP2D30\!TC\,QT.W#MIAW*6R01$\%!/'94(V&O(OX57-3D<31?]30'Q#">+6 M->7(M@:S6:;4W07:1K)L/;,&NF!]L9/QZC:X9,K8N]=,(UR#;[7_VLY]"=-^M^FB97%Y/I&2"\,#]^$:??F33J5/[<+0-+FI3\G3P-+LV74A+(NY#%84G8(EKL' M,'KA>=PAD'87VW4"1/M93^_T$5CA&ES9H95(%PW%E\BVS)F5]HI%7=)CHC5Q M&$<"UD(.Q\BU!LE"Q;NA5;>=K8/YX`\.YM,DR&=P44LS-E\>C_!1]A`'57_S MY8"P7]^1Z669!V\&M3N:)IF-HZ'P'3^M$IK9NVH:9%W*S^]I:KO#O:`\>%^Z M&?E;2)217Q1Z+VQUG/5I@%CNH#=!K,EXU&+'R%5JUEJZ.-A6VMY(>Q2D MI!>BUYR!G@BV_F?]:F7Z#'J`LFSZNQKG*$S6'4^F($*RS,=1>(;TYVEL/LZ2 M*(*>SQ>+)(-@/1CH.GIY=Y`LXWS=8RX_GEK_!8;R=!GDY2'XYX:*9@,^&N+P M^<6ZC['GLI/Y6/4R7Z#;BC*,K.]9C9JJ'$!\`<(,SI];`[CEKTJ36BS+0<_, MD?)[4$6D#_=+<^)\FJ'D;C32W<]UNJ-)H$LT?/OZU9MW0'S%)C1%MRH_,;*? MZO8(G?QI=?$4I+]-\D2S6%TZ65T;OHS&W91CEXJX1#5J(9A4^C!\&:ZU4?%BOK>0KO.J*20+5!1HNV7X MLL+[,=YT#2`;ERH<2[#3DWF>;8W0#SO#Y:\K6;5WT)?U M.S#R;-L2-OV,DQ@,X`UZ03G3OOR#E`M!+X]=.$3BV^@#O0:6@V[_#K>9>?B+(**/"6 M*0@?]6!B`LB6UR\_P^MV!%B+75(I\=D"$2;_&!*M5/[;1_QGZ[M4_QM^__WY\\^['TQ>[3&B5&B;, M'7N8V&BX9ARZY1%6OO_YYJ:#E1X(.7Q?U.\'TD'`Z$-O8_W<6:F99S75E.,D MT4E)_?0Q51T`$?[2P&@&5HEU[9!KK[SZX..U[86U!AF;4LC*X7\!_X_=^_I2 M)0QS&KB94->$/&Z)=,@*:?/X2"\<#WULI;T4M4NE*D3ILV!$/*V*=_F431/% MC8Q'E3`<<5`-8W.PNA^,!Q[H[H"QL1%=GK1U"H;AMJ=TNJ<\?MZ"XB<=)C`G MMOI-Q>83FON!//(1T=V*1??#H571PL;@JLI9:1_J7.EGK%G`"B()EX%ZY!GY MH7X<&RU2R&3UCQ"8Q].[BU;Z&=@=(VAJYZ@-9;LTA56&KCU2_*4IOMPL/YYA!T#J&OG MJ-U30O61M6OS3JT#G,%Z(;[5NEZHKXJD\&>K=KJSAM+C<\3,^.;,C"D'ARH+ MTND"<-'56?CRPG1T$;7