NTFS: 2.0.15 - Fake inodes based attribute i/o via the page cache, fixes, cleanups

From: Anton Altaparmakov (aia21@cantab.net)
Date: Mon Jul 08 2002 - 12:47:31 EST


Linus, please do a

        bk pull http://linux-ntfs.bkbits.net/ntfs-tng-2.5

Thanks!

Fake inode based i/o is now fully implemented. Only cleanups left to do
but the patch was getting big so I stopped here...

Best regards,

        Anton

-- 
Anton Altaparmakov <aia21 at cantab.net> (replace at with @)
Linux NTFS maintainer / IRC: #ntfs on irc.openprojects.net
WWW: http://linux-ntfs.sf.net/, http://www-stu.christs.cam.ac.uk/~aia21/

===================================================================

This will update the following files:

Documentation/filesystems/ntfs.txt | 5 fs/ntfs/ChangeLog | 29 +++ fs/ntfs/Makefile | 2 fs/ntfs/aops.c | 135 +++++---------- fs/ntfs/attrib.c | 55 +----- fs/ntfs/compress.c | 5 fs/ntfs/inode.c | 321 ++++++++++++++++++++++++++++++++++++- fs/ntfs/mft.c | 18 +- fs/ntfs/ntfs.h | 19 +- fs/ntfs/super.c | 13 - fs/ntfs/volume.h | 58 +++--- 11 files changed, 481 insertions(+), 179 deletions(-)

through these ChangeSets:

<aia21@cantab.net> (02/07/08 1.617) NTFS: 2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes, cleanups. - Fix silly bug in fs/ntfs/super.c::parse_options() which was causing remounts to fail when the partition had an entry in /etc/fstab and the entry specified the nls= option. - Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to expand all the helper functions NVolFoo(), NVolSetFoo(), and NVolClearFoo(). - Move copyright statement from driver initialisation message to module description (fs/super.c). This makes the initialisation message fit on one line and fits in better with rest of kernel. - Update fs/ntfs/attrib.c::map_run_list() to work on both real and attribute inodes, and both for files and directories. - Implement fake attribute inodes allowing all attribute i/o to go via the page cache and to use all the normal vfs/mm functionality: - Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode() to fs/ntfs/inode.c. - Add needed cleanup code to ntfs_clear_big_inode(). - Merge address space operations for files and directories (aops.c), now just have ntfs_aops: - Rename: end_buffer_read_attr_async() -> ntfs_end_buffer_read_async(), ntfs_attr_read_block() -> ntfs_read_block(), ntfs_file_read_page() -> ntfs_readpage(). - Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and attribute inodes, and both for files and directories. - Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage().

diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt Mon Jul 8 18:41:18 2002 +++ b/Documentation/filesystems/ntfs.txt Mon Jul 8 18:41:18 2002 @@ -247,6 +247,11 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.0.15: + - Bug fix in parsing of remount options. + - Internal changes implementing attribute (fake) inodes allowing all + attribute i/o to go via the page cache and to use all the normal + vfs/mm functionality. 2.0.14: - Internal changes improving run list merging code and minor locking change to not rely on BKL in ntfs_statfs(). diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/ChangeLog Mon Jul 8 18:41:18 2002 @@ -26,7 +26,34 @@ callers, i.e. ntfs_iget(), to pass that error code up instead of just using -EIO. - Enable NFS exporting of NTFS. - - Use fake inodes for address space i/o. + +2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes and cleanups. + + - Fix silly bug in fs/ntfs/super.c::parse_options() which was causing + remounts to fail when the partition had an entry in /etc/fstab and + the entry specified the nls= option. + - Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to + expand all the helper functions NVolFoo(), NVolSetFoo(), and + NVolClearFoo(). + - Move copyright statement from driver initialisation message to + module description (fs/super.c). This makes the initialisation + message fit on one line and fits in better with rest of kernel. + - Update fs/ntfs/attrib.c::map_run_list() to work on both real and + attribute inodes, and both for files and directories. + - Implement fake attribute inodes allowing all attribute i/o to go via + the page cache and to use all the normal vfs/mm functionality: + - Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode() + to fs/ntfs/inode.c. + - Add needed cleanup code to ntfs_clear_big_inode(). + - Merge address space operations for files and directories (aops.c), + now just have ntfs_aops: + - Rename: + end_buffer_read_attr_async() -> ntfs_end_buffer_read_async(), + ntfs_attr_read_block() -> ntfs_read_block(), + ntfs_file_read_page() -> ntfs_readpage(). + - Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and + attribute inodes, and both for files and directories. + - Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage(). 2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes. diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/Makefile Mon Jul 8 18:41:18 2002 @@ -5,7 +5,7 @@ ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.14\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.15\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c --- a/fs/ntfs/aops.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/aops.c Mon Jul 8 18:41:18 2002 @@ -30,7 +30,7 @@ #include "ntfs.h" /** - * end_buffer_read_attr_async - async io completion for reading attributes + * ntfs_end_buffer_read_async - async io completion for reading attributes * @bh: buffer head on which io is completed * @uptodate: whether @bh is now uptodate or not * @@ -45,7 +45,7 @@ * record size, and index_block_size_bits, to the log(base 2) of the ntfs * record size. */ -static void end_buffer_read_attr_async(struct buffer_head *bh, int uptodate) +static void ntfs_end_buffer_read_async(struct buffer_head *bh, int uptodate) { static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED; unsigned long flags; @@ -143,12 +143,12 @@ } /** - * ntfs_attr_read_block - fill a @page of an address space with data + * ntfs_read_block - fill a @page of an address space with data * @page: page cache page to fill with data * * Fill the page @page of the address space belonging to the @page->host inode. * We read each buffer asynchronously and when all buffers are read in, our io - * completion handler end_buffer_read_attr_async(), if required, automatically + * completion handler ntfs_end_buffer_read_async(), if required, automatically * applies the mst fixups to the page before finally marking it uptodate and * unlocking it. * @@ -156,7 +156,7 @@ * * Contains an adapted version of fs/buffer.c::block_read_full_page(). */ -static int ntfs_attr_read_block(struct page *page) +static int ntfs_read_block(struct page *page) { VCN vcn; LCN lcn; @@ -267,7 +267,7 @@ for (i = 0; i < nr; i++) { struct buffer_head *tbh = arr[i]; lock_buffer(tbh); - tbh->b_end_io = end_buffer_read_attr_async; + tbh->b_end_io = ntfs_end_buffer_read_async; set_buffer_async_read(tbh); } /* Finally, start i/o on the buffers. */ @@ -285,27 +285,27 @@ } /** - * ntfs_file_readpage - fill a @page of a @file with data from the device + * ntfs_readpage - fill a @page of a @file with data from the device * @file: open file to which the page @page belongs or NULL * @page: page cache page to fill with data * - * For non-resident attributes, ntfs_file_readpage() fills the @page of the open + * For non-resident attributes, ntfs_readpage() fills the @page of the open * file @file by calling the ntfs version of the generic block_read_full_page() - * function provided by the kernel, ntfs_attr_read_block(), which in turn - * creates and reads in the buffers associated with the page asynchronously. + * function, ntfs_read_block(), which in turn creates and reads in the buffers + * associated with the page asynchronously. * - * For resident attributes, OTOH, ntfs_file_readpage() fills @page by copying - * the data from the mft record (which at this stage is most likely in memory) - * and fills the remainder with zeroes. Thus, in this case, I/O is synchronous, - * as even if the mft record is not cached at this point in time, we need to - * wait for it to be read in before we can do the copy. + * For resident attributes, OTOH, ntfs_readpage() fills @page by copying the + * data from the mft record (which at this stage is most likely in memory) and + * fills the remainder with zeroes. Thus, in this case, I/O is synchronous, as + * even if the mft record is not cached at this point in time, we need to wait + * for it to be read in before we can do the copy. * - * Return 0 on success or -errno on error. + * Return 0 on success and -errno on error. */ -static int ntfs_file_readpage(struct file *file, struct page *page) +int ntfs_readpage(struct file *file, struct page *page) { s64 attr_pos; - ntfs_inode *ni; + ntfs_inode *ni, *base_ni; char *addr; attr_search_context *ctx; MFT_RECORD *mrec; @@ -317,40 +317,45 @@ ni = NTFS_I(page->mapping->host); - /* Is the unnamed $DATA attribute resident? */ if (NInoNonResident(ni)) { - /* Attribute is not resident. */ - - /* If the file is encrypted, we deny access, just like NT4. */ - if (NInoEncrypted(ni)) { - err = -EACCES; - goto unl_err_out; - } - /* Compressed data stream. Handled in compress.c. */ - if (NInoCompressed(ni)) - return ntfs_file_read_compressed_block(page); + /* + * Only unnamed $DATA attributes can be compressed or + * encrypted. + */ + if (ni->type == AT_DATA && !ni->name_len) { + /* If file is encrypted, deny access, just like NT4. */ + if (NInoEncrypted(ni)) { + err = -EACCES; + goto err_out; + } + /* Compressed data streams are handled in compress.c. */ + if (NInoCompressed(ni)) + return ntfs_file_read_compressed_block(page); + } /* Normal data stream. */ - return ntfs_attr_read_block(page); + return ntfs_read_block(page); } /* Attribute is resident, implying it is not compressed or encrypted. */ + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->_INE(base_ntfs_ino); /* Map, pin and lock the mft record for reading. */ - mrec = map_mft_record(READ, ni); + mrec = map_mft_record(READ, base_ni); if (unlikely(IS_ERR(mrec))) { err = PTR_ERR(mrec); - goto unl_err_out; + goto err_out; } - - ctx = get_attr_search_ctx(ni, mrec); + ctx = get_attr_search_ctx(base_ni, mrec); if (unlikely(!ctx)) { err = -ENOMEM; - goto unm_unl_err_out; + goto unm_err_out; } - - /* Find the data attribute in the mft record. */ - if (unlikely(!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx))) { + if (unlikely(!lookup_attr(ni->type, ni->name, ni->name_len, + IGNORE_CASE, 0, NULL, 0, ctx))) { err = -ENOENT; - goto put_unm_unl_err_out; + goto put_unm_err_out; } /* Starting position of the page within the attribute value. */ @@ -377,35 +382,16 @@ kunmap(page); SetPageUptodate(page); -put_unm_unl_err_out: +put_unm_err_out: put_attr_search_ctx(ctx); -unm_unl_err_out: - unmap_mft_record(READ, ni); -unl_err_out: +unm_err_out: + unmap_mft_record(READ, base_ni); +err_out: unlock_page(page); return err; } /** - * ntfs_mst_readpage - fill a @page of the mft or a directory with data - * @file: open file/directory to which the @page belongs or NULL - * @page: page cache page to fill with data - * - * Readpage method for the VFS address space operations of directory inodes - * and the $MFT/$DATA attribute. - * - * We just call ntfs_attr_read_block() here, in fact we only need this wrapper - * because of the difference in function parameters. - */ -int ntfs_mst_readpage(struct file *file, struct page *page) -{ - if (unlikely(!PageLocked(page))) - PAGE_BUG(page); - - return ntfs_attr_read_block(page); -} - -/** * end_buffer_read_mftbmp_async - * * Async io completion handler for accessing mft bitmap. Adapted from @@ -473,7 +459,7 @@ /** * ntfs_mftbmp_readpage - * - * Readpage for accessing mft bitmap. Adapted from ntfs_mst_readpage(). + * Readpage for accessing mft bitmap. */ static int ntfs_mftbmp_readpage(ntfs_volume *vol, struct page *page) { @@ -587,11 +573,11 @@ } /** - * ntfs_file_aops - address space operations for accessing normal file data + * ntfs_aops - general address space operations for inodes and attributes */ -struct address_space_operations ntfs_file_aops = { +struct address_space_operations ntfs_aops = { writepage: NULL, /* Write dirty page to disk. */ - readpage: ntfs_file_readpage, /* Fill page with data. */ + readpage: ntfs_readpage, /* Fill page with data. */ sync_page: block_sync_page, /* Currently, just unplugs the disk request queue. */ prepare_write: NULL, /* . */ @@ -607,23 +593,6 @@ writepage: NULL, /* Write dirty page to disk. */ readpage: (readpage_t*)ntfs_mftbmp_readpage, /* Fill page with data. */ - sync_page: block_sync_page, /* Currently, just unplugs the - disk request queue. */ - prepare_write: NULL, /* . */ - commit_write: NULL, /* . */ -}; - -/** - * ntfs_dir_aops - - * - * Address space operations for accessing normal directory data (i.e. index - * allocation attribute). We can't just use the same operations as for files - * because 1) the attribute is different and even more importantly 2) the index - * records have to be multi sector transfer deprotected (i.e. fixed-up). - */ -struct address_space_operations ntfs_dir_aops = { - writepage: NULL, /* Write dirty page to disk. */ - readpage: ntfs_mst_readpage, /* Fill page with data. */ sync_page: block_sync_page, /* Currently, just unplugs the disk request queue. */ prepare_write: NULL, /* . */ diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c --- a/fs/ntfs/attrib.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/attrib.c Mon Jul 8 18:41:18 2002 @@ -935,78 +935,51 @@ */ int map_run_list(ntfs_inode *ni, VCN vcn) { + ntfs_inode *base_ni; attr_search_context *ctx; MFT_RECORD *mrec; - const uchar_t *name; - u32 name_len; - ATTR_TYPES at; int err = 0; ntfs_debug("Mapping run list part containing vcn 0x%Lx.", (long long)vcn); - /* Map, pin and lock the mft record for reading. */ - mrec = map_mft_record(READ, ni); + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->_INE(base_ntfs_ino); + + mrec = map_mft_record(READ, base_ni); if (IS_ERR(mrec)) return PTR_ERR(mrec); - - ctx = get_attr_search_ctx(ni, mrec); + ctx = get_attr_search_ctx(base_ni, mrec); if (!ctx) { err = -ENOMEM; - goto unm_err_out; - } - - /* The attribute type is determined from the inode type. */ - if (S_ISDIR(VFS_I(ni)->i_mode)) { - at = AT_INDEX_ALLOCATION; - name = I30; - name_len = 4; - } else { - at = AT_DATA; - name = NULL; - name_len = 0; + goto err_out; } - - /* Find the attribute in the mft record. */ - if (!lookup_attr(at, name, name_len, CASE_SENSITIVE, vcn, NULL, 0, - ctx)) { + if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, vcn, + NULL, 0, ctx)) { put_attr_search_ctx(ctx); err = -ENOENT; - goto unm_err_out; + goto err_out; } - /* Lock the run list. */ down_write(&ni->run_list.lock); - /* Make sure someone else didn't do the work while we were spinning. */ if (likely(vcn_to_lcn(ni->run_list.rl, vcn) <= LCN_RL_NOT_MAPPED)) { run_list_element *rl; - /* Decode the run list. */ rl = decompress_mapping_pairs(ni->vol, ctx->attr, ni->run_list.rl); - - /* Flag any errors or set the run list if successful. */ if (unlikely(IS_ERR(rl))) err = PTR_ERR(rl); else ni->run_list.rl = rl; } - - /* Unlock the run list. */ up_write(&ni->run_list.lock); put_attr_search_ctx(ctx); - - /* Unlock, unpin and release the mft record. */ - unmap_mft_record(READ, ni); - - /* If an error occured, return it. */ - ntfs_debug("Done."); - return err; - -unm_err_out: - unmap_mft_record(READ, ni); +err_out: + unmap_mft_record(READ, base_ni); return err; } diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c --- a/fs/ntfs/compress.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/compress.c Mon Jul 8 18:41:18 2002 @@ -462,6 +462,11 @@ ntfs_debug("Entering, page->index = 0x%lx, cb_size = 0x%x, nr_pages = " "%i.", index, cb_size, nr_pages); + /* + * Bad things happen if we get here for anything that is not an + * unnamed $DATA attribute. + */ + BUG_ON(ni->type != AT_DATA || ni->name_len); pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS); diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/inode.c Mon Jul 8 18:41:18 2002 @@ -35,7 +35,7 @@ * @type: attribute type (see layout.h) * * This structure exists only to provide a small structure for the - * ntfs_iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism. + * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism. * * NOTE: Elements are ordered by size to make the structure as compact as * possible on all architectures. @@ -112,14 +112,21 @@ ntfs_inode *ni = NTFS_I(vi); vi->i_ino = na->mft_no; + ni->type = na->type; + if (na->type == AT_INDEX_ALLOCATION) + NInoSetMstProtected(ni); + ni->name = na->name; ni->name_len = na->name_len; + /* If initializing a normal inode, we are done. */ if (likely(na->type == AT_UNUSED)) return 0; + /* It is a fake inode. */ NInoSetAttr(ni); + /* * We have I30 global constant as an optimization as it is the name * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC @@ -143,6 +150,7 @@ typedef int (*test_t)(struct inode *, void *); typedef int (*set_t)(struct inode *, void *); static void ntfs_read_locked_inode(struct inode *vi); +static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi); /** * ntfs_iget - obtain a struct inode corresponding to a specific normal inode @@ -197,6 +205,62 @@ return vi; } +/** + * ntfs_attr_iget - obtain a struct inode corresponding to an attribute + * @base_vi: vfs base inode containing the attribute + * @type: attribute type + * @name: Unicode name of the attribute (NULL if unnamed) + * @name_len: length of @name in Unicode characters (0 if unnamed) + * + * Obtain the (fake) struct inode corresponding to the attribute specified by + * @type, @name, and @name_len, which is present in the base mft record + * specified by the vfs inode @base_vi. + * + * If the attribute inode is in the cache, it is just returned with an + * increased reference count. Otherwise, a new struct inode is allocated and + * initialized, and finally ntfs_read_locked_attr_inode() is called to read the + * attribute and fill in the inode structure. + * + * Return the struct inode of the attribute inode on success. Check the return + * value with IS_ERR() and if true, the function failed and the error code is + * obtained from PTR_ERR(). + */ +struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type, + uchar_t *name, u32 name_len) +{ + struct inode *vi; + ntfs_attr na; + int err; + + na.mft_no = base_vi->i_ino; + na.type = type; + na.name = name; + na.name_len = name_len; + + vi = iget5_locked(base_vi->i_sb, na.mft_no, (test_t)ntfs_test_inode, + (set_t)ntfs_init_locked_inode, &na); + if (!vi) + return ERR_PTR(-ENOMEM); + + err = 0; + + /* If this is a freshly allocated inode, need to read it now. */ + if (vi->i_state & I_NEW) { + err = ntfs_read_locked_attr_inode(base_vi, vi); + unlock_new_inode(vi); + } + /* + * There is no point in keeping bad attribute inodes around. This also + * simplifies things in that we never need to check for bad attribute + * inodes elsewhere. + */ + if (err) { + iput(vi); + vi = ERR_PTR(-EIO); + } + return vi; +} + struct inode *ntfs_alloc_big_inode(struct super_block *sb) { ntfs_inode *ni; @@ -685,9 +749,8 @@ goto put_unm_err_out; } if (ir->type != AT_FILE_NAME) { - ntfs_error(vi->i_sb, __FUNCTION__ "(): Indexed " - "attribute is not $FILE_NAME. Not " - "allowed."); + ntfs_error(vi->i_sb, "Indexed attribute is not " + "$FILE_NAME. Not allowed."); goto put_unm_err_out; } if (ir->collation_rule != COLLATION_FILE_NAME) { @@ -856,7 +919,7 @@ /* Setup the operations for this inode. */ vi->i_op = &ntfs_dir_inode_ops; vi->i_fop = &ntfs_dir_ops; - vi->i_mapping->a_ops = &ntfs_dir_aops; + vi->i_mapping->a_ops = &ntfs_aops; } else { /* It is a file. */ reinit_attr_search_ctx(ctx); @@ -995,7 +1058,7 @@ /* Setup the operations for this inode. */ vi->i_op = &ntfs_file_inode_ops; vi->i_fop = &ntfs_file_ops; - vi->i_mapping->a_ops = &ntfs_file_aops; + vi->i_mapping->a_ops = &ntfs_aops; } /* * The number of 512-byte blocks used on disk (for stat). This is in so @@ -1034,6 +1097,245 @@ } /** + * ntfs_read_locked_attr_inode - read an attribute inode from its base inode + * @base_vi: base inode + * @vi: attribute inode to read + * + * ntfs_read_locked_attr_inode() is called from the ntfs_attr_iget() to read + * the attribute inode described by @vi into memory from the base mft record + * described by @base_ni. + * + * ntfs_read_locked_attr_inode() maps, pins and locks the base inode for + * reading and looks up the attribute described by @vi before setting up the + * necessary fields in @vi as well as initializing the ntfs inode. + * + * Q: What locks are held when the function is called? + * A: i_state has I_LOCK set, hence the inode is locked, also + * i_count is set to 1, so it is not going to go away + */ +static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) +{ + ntfs_volume *vol = NTFS_SB(vi->i_sb); + ntfs_inode *ni, *base_ni; + MFT_RECORD *m; + attr_search_context *ctx; + int err = 0; + + ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); + + ntfs_init_big_inode(vi); + + ni = NTFS_I(vi); + base_ni = NTFS_I(base_vi); + + /* Just mirror the values from the base inode. */ + vi->i_blksize = base_vi->i_blksize; + vi->i_version = base_vi->i_version; + vi->i_uid = base_vi->i_uid; + vi->i_gid = base_vi->i_gid; + vi->i_nlink = base_vi->i_nlink; + vi->i_mtime = base_vi->i_mtime; + vi->i_ctime = base_vi->i_ctime; + vi->i_atime = base_vi->i_atime; + ni->seq_no = base_ni->seq_no; + + /* Set inode type to zero but preserve permissions. */ + vi->i_mode = base_vi->i_mode & ~S_IFMT; + + m = map_mft_record(READ, base_ni); + if (IS_ERR(m)) { + err = PTR_ERR(m); + goto err_out; + } + ctx = get_attr_search_ctx(base_ni, m); + if (!ctx) { + err = -ENOMEM; + goto unm_err_out; + } + + /* Find the attribute. */ + if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, 0, + NULL, 0, ctx)) + goto unm_err_out; + + if (!ctx->attr->non_resident) { + if (NInoMstProtected(ni) || ctx->attr->flags) { + ntfs_error(vi->i_sb, "Found mst protected attribute " + "or attribute with non-zero flags but " + "the attribute is resident (mft_no " + "0x%lx, type 0x%x, name_len %i). " + "Please report you saw this message " + "to linux-ntfs-dev@lists.sf.net", + vi->i_ino, ni->type, ni->name_len); + goto unm_err_out; + } + /* + * Resident attribute. Make all sizes equal for simplicity in + * read code paths. + */ + vi->i_size = ni->initialized_size = ni->allocated_size = + le32_to_cpu(ctx->attr->_ARA(value_length)); + } else { + NInoSetNonResident(ni); + if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + if (NInoMstProtected(ni)) { + ntfs_error(vi->i_sb, "Found mst protected " + "attribute but the attribute " + "is compressed (mft_no 0x%lx, " + "type 0x%x, name_len %i). " + "Please report you saw this " + "message to linux-ntfs-dev@" + "lists.sf.net", vi->i_ino, + ni->type, ni->name_len); + goto unm_err_out; + } + NInoSetCompressed(ni); + if ((ni->type != AT_DATA) || (ni->type == AT_DATA && + ni->name_len)) { + ntfs_error(vi->i_sb, "Found compressed non-" + "data or named data attribute " + "(mft_no 0x%lx, type 0x%x, " + "name_len %i). Please report " + "you saw this message to " + "linux-ntfs-dev@lists.sf.net", + vi->i_ino, ni->type, + ni->name_len); + goto unm_err_out; + } + if (vol->cluster_size > 4096) { + ntfs_error(vi->i_sb, "Found " + "compressed attribute but " + "compression is disabled due " + "to cluster size (%i) > 4kiB.", + vol->cluster_size); + goto unm_err_out; + } + if ((ctx->attr->flags & ATTR_COMPRESSION_MASK) + != ATTR_IS_COMPRESSED) { + ntfs_error(vi->i_sb, "Found unknown " + "compression method or " + "corrupt file."); + goto unm_err_out; + } + ni->_ICF(compression_block_clusters) = 1U << + ctx->attr->_ANR(compression_unit); + if (ctx->attr->_ANR(compression_unit) != 4) { + ntfs_error(vi->i_sb, "Found " + "nonstandard compression unit " + "(%u instead of 4). Cannot " + "handle this. This might " + "indicate corruption so you " + "should run chkdsk.", + ctx->attr->_ANR(compression_unit)); + err = -EOPNOTSUPP; + goto unm_err_out; + } + ni->_ICF(compression_block_size) = 1U << ( + ctx->attr->_ANR( + compression_unit) + + vol->cluster_size_bits); + ni->_ICF(compression_block_size_bits) = ffs( + ni->_ICF(compression_block_size)) - 1; + } + if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { + if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + ntfs_error(vi->i_sb, "Found encrypted " + "and compressed data."); + goto unm_err_out; + } + if (NInoMstProtected(ni)) { + ntfs_error(vi->i_sb, "Found mst protected " + "attribute but the attribute " + "is encrypted (mft_no 0x%lx, " + "type 0x%x, name_len %i). " + "Please report you saw this " + "message to linux-ntfs-dev@" + "lists.sf.net", vi->i_ino, + ni->type, ni->name_len); + goto unm_err_out; + } + NInoSetEncrypted(ni); + } + if (ctx->attr->flags & ATTR_IS_SPARSE) { + if (NInoMstProtected(ni)) { + ntfs_error(vi->i_sb, "Found mst protected " + "attribute but the attribute " + "is sparse (mft_no 0x%lx, " + "type 0x%x, name_len %i). " + "Please report you saw this " + "message to linux-ntfs-dev@" + "lists.sf.net", vi->i_ino, + ni->type, ni->name_len); + goto unm_err_out; + } + NInoSetSparse(ni); + } + if (ctx->attr->_ANR(lowest_vcn)) { + ntfs_error(vi->i_sb, "First extent of attribute has " + "non-zero lowest_vcn. Inode is " + "corrupt. You should run chkdsk."); + goto unm_err_out; + } + /* Setup all the sizes. */ + vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size)); + ni->initialized_size = sle64_to_cpu( + ctx->attr->_ANR(initialized_size)); + ni->allocated_size = sle64_to_cpu( + ctx->attr->_ANR(allocated_size)); + if (NInoCompressed(ni)) { + ni->_ICF(compressed_size) = sle64_to_cpu( + ctx->attr->_ANR(compressed_size)); + if (vi->i_size != ni->initialized_size) + ntfs_warning(vi->i_sb, "Compressed attribute " + "with data_size unequal to " + "initialized size found. This " + "will probably cause problems " + "when trying to access the " + "file. Please notify " + "linux-ntfs-dev@ lists.sf.net " + "that you saw this message."); + } + } + + /* Setup the operations for this attribute inode. */ + vi->i_op = NULL; + vi->i_fop = NULL; + vi->i_mapping->a_ops = &ntfs_aops; + + if (!NInoCompressed(ni)) + vi->i_blocks = ni->allocated_size >> 9; + else + vi->i_blocks = ni->_ICF(compressed_size) >> 9; + + /* + * Make sure the base inode doesn't go away and attach it to the + * attribute inode. + */ + igrab(base_vi); + ni->_INE(base_ntfs_ino) = base_ni; + ni->nr_extents = -1; + + put_attr_search_ctx(ctx); + unmap_mft_record(READ, ni); + + ntfs_debug("Done."); + return 0; + +unm_err_out: + if (!err) + err = -EIO; + if (ctx) + put_attr_search_ctx(ctx); + unmap_mft_record(READ, base_ni); +err_out: + ntfs_error(vi->i_sb, "Failed with error code %i while reading " + "attribute inode (mft_no 0x%lx, type 0x%x, name_len " + "%i.", -err, vi->i_ino, ni->type, ni->name_len); + make_bad_inode(vi); + return err; +} + +/** * ntfs_read_inode_mount - special read_inode for mount time use only * @vi: inode to read * @@ -1590,6 +1892,13 @@ if (ni->_IDM(bmp_rl).rl) ntfs_free(ni->_IDM(bmp_rl).rl); up_write(&ni->_IDM(bmp_rl).lock); + } else if (NInoAttr(ni)) { + /* Release the base inode if we are holding it. */ + if (ni->nr_extents == -1) { + iput(VFS_I(ni->_INE(base_ntfs_ino))); + ni->nr_extents = 0; + ni->_INE(base_ntfs_ino) = NULL; + } } return; } diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c --- a/fs/ntfs/mft.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/mft.c Mon Jul 8 18:41:18 2002 @@ -95,8 +95,10 @@ return 0; } -/* From fs/ntfs/aops.c */ -extern int ntfs_mst_readpage(struct file *, struct page *); +/** + * From fs/ntfs/aops.c + */ +extern int ntfs_readpage(struct file *, struct page *); /** * ntfs_mft_aops - address space operations for access to $MFT @@ -106,7 +108,7 @@ */ struct address_space_operations ntfs_mft_aops = { writepage: NULL, /* Write dirty page to disk. */ - readpage: ntfs_mst_readpage, /* Fill page with data. */ + readpage: ntfs_readpage, /* Fill page with data. */ sync_page: block_sync_page, /* Currently, just unplugs the disk request queue. */ prepare_write: NULL, /* . */ @@ -214,11 +216,11 @@ * necessary, increments the use count on the page so that it cannot disappear * under us and returns a reference to the page cache page). * - * If read_cache_page() invokes ntfs_mst_readpage() to load the page from disk, - * it sets PG_locked and clears PG_uptodate on the page. Once I/O has - * completed and the post-read mst fixups on each mft record in the page have - * been performed, the page gets PG_uptodate set and PG_locked cleared (this is - * done in our asynchronous I/O completion handler end_buffer_read_mft_async()). + * If read_cache_page() invokes ntfs_readpage() to load the page from disk, it + * sets PG_locked and clears PG_uptodate on the page. Once I/O has completed + * and the post-read mst fixups on each mft record in the page have been + * performed, the page gets PG_uptodate set and PG_locked cleared (this is done + * in our asynchronous I/O completion handler end_buffer_read_mft_async()). * ntfs_map_page() waits for PG_locked to become clear and checks if * PG_uptodate is set and returns an error code if not. This provides * sufficient protection against races when reading/using the page. diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h --- a/fs/ntfs/ntfs.h Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/ntfs.h Mon Jul 8 18:41:18 2002 @@ -62,18 +62,21 @@ extern kmem_cache_t *ntfs_attr_ctx_cache; /* The various operations structs defined throughout the driver files. */ -extern struct super_operations ntfs_mount_sops; extern struct super_operations ntfs_sops; -extern struct file_operations ntfs_file_ops; +extern struct super_operations ntfs_mount_sops; + +extern struct address_space_operations ntfs_aops; +extern struct address_space_operations ntfs_mft_aops; +extern struct address_space_operations ntfs_mftbmp_aops; + +extern struct file_operations ntfs_file_ops; extern struct inode_operations ntfs_file_inode_ops; -extern struct address_space_operations ntfs_file_aops; -extern struct file_operations ntfs_dir_ops; + +extern struct file_operations ntfs_dir_ops; extern struct inode_operations ntfs_dir_inode_ops; -extern struct address_space_operations ntfs_dir_aops; -extern struct file_operations ntfs_empty_file_ops; + +extern struct file_operations ntfs_empty_file_ops; extern struct inode_operations ntfs_empty_inode_ops; -extern struct address_space_operations ntfs_mft_aops; -extern struct address_space_operations ntfs_mftbmp_aops; /* Generic macro to convert pointers to values for comparison purposes. */ #ifndef p2n diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c --- a/fs/ntfs/super.c Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/super.c Mon Jul 8 18:41:18 2002 @@ -135,6 +135,7 @@ } if (!opt || !*opt) goto no_mount_options; + ntfs_debug("Entering with mount options string: %s", opt); while ((p = strsep(&opt, ","))) { if ((v = strchr(p, '='))) *v++ = '\0'; @@ -217,7 +218,7 @@ } } if (nls_map) { - if (vol->nls_map) { + if (vol->nls_map && vol->nls_map != nls_map) { ntfs_error(vol->sb, "Cannot change NLS character set " "on remount."); return FALSE; @@ -249,8 +250,8 @@ mft_zone_multiplier = 1; } vol->mft_zone_multiplier = mft_zone_multiplier; - } if (!vol->mft_zone_multiplier) - /* Not specified and it is the first mount, so set default. */ + } + if (!vol->mft_zone_multiplier) vol->mft_zone_multiplier = 1; if (on_errors != -1) vol->on_errors = on_errors; @@ -304,7 +305,7 @@ { ntfs_volume *vol = NTFS_SB(sb); - ntfs_debug("Entering."); + ntfs_debug("Entering with remount options string: %s", opt); // FIXME/TODO: If left like this we will have problems with rw->ro and // ro->rw, as well as with sync->async and vice versa remounts. @@ -1799,7 +1800,7 @@ #ifdef MODULE " MODULE" #endif - "]. Copyright (c) 2001,2002 Anton Altaparmakov.\n"); + "].\n"); ntfs_debug("Debug messages are enabled."); @@ -1899,7 +1900,7 @@ } MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); -MODULE_DESCRIPTION("NTFS 1.2/3.x driver"); +MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2002 Anton Altaparmakov"); MODULE_LICENSE("GPL"); #ifdef DEBUG MODULE_PARM(debug_msgs, "i"); diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h --- a/fs/ntfs/volume.h Mon Jul 8 18:41:18 2002 +++ b/fs/ntfs/volume.h Mon Jul 8 18:41:18 2002 @@ -27,31 +27,6 @@ #include "types.h" /* - * Defined bits for the flags field in the ntfs_volume structure. - */ -typedef enum { - NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */ - NV_CaseSensitive, /* 1: Treat file names as case sensitive and - create filenames in the POSIX namespace. - Otherwise be case insensitive and create - file names in WIN32 namespace. */ -} ntfs_volume_flags; - -#define NVolShowSystemFiles(n_vol) test_bit(NV_ShowSystemFiles, \ - &(n_vol)->flags) -#define NVolSetShowSystemFiles(n_vol) set_bit(NV_ShowSystemFiles, \ - &(n_vol)->flags) -#define NVolClearShowSystemFiles(n_vol) clear_bit(NV_ShowSystemFiles, \ - &(n_vol)->flags) - -#define NVolCaseSensitive(n_vol) test_bit(NV_CaseSensitive, \ - &(n_vol)->flags) -#define NVolSetCaseSensitive(n_vol) set_bit(NV_CaseSensitive, \ - &(n_vol)->flags) -#define NVolClearCaseSensitive(n_vol) clear_bit(NV_CaseSensitive, \ - &(n_vol)->flags) - -/* * The NTFS in memory super block structure. */ typedef struct { @@ -123,6 +98,39 @@ only, otherwise NULL). */ struct nls_table *nls_map; } ntfs_volume; + +/* + * Defined bits for the flags field in the ntfs_volume structure. + */ +typedef enum { + NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */ + NV_CaseSensitive, /* 1: Treat file names as case sensitive and + create filenames in the POSIX namespace. + Otherwise be case insensitive and create + file names in WIN32 namespace. */ +} ntfs_volume_flags; + +/* + * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo() + * functions. + */ +#define NVOL_FNS(flag) \ +static inline int NVol##flag(ntfs_volume *vol) \ +{ \ + return test_bit(NV_##flag, &(vol)->flags); \ +} \ +static inline void NVolSet##flag(ntfs_volume *vol) \ +{ \ + set_bit(NV_##flag, &(vol)->flags); \ +} \ +static inline void NVolClear##flag(ntfs_volume *vol) \ +{ \ + clear_bit(NV_##flag, &(vol)->flags); \ +} + +/* Emit the ntfs volume bitops functions. */ +NVOL_FNS(ShowSystemFiles) +NVOL_FNS(CaseSensitive) #endif /* _LINUX_NTFS_VOLUME_H */

===================================================================

This BitKeeper patch contains the following changesets: aia21@cantab.net|ChangeSet|20020708174011|11655 aia21@cantab.net|ChangeSet|20020706233736|11639 aia21@cantab.net|ChangeSet|20020705235849|62477 aia21@cantab.net|ChangeSet|20020705200106|53559 aia21@cantab.net|ChangeSet|20020705120813|47863 aia21@cantab.net|ChangeSet|20020704223115|00790 ## Wrapped with gzip_uu ##

begin 664 bkpatch634 M'XL(`+[.*3T``]0\:7/;1I:?P5_1\<RX)`]%X09!E[V2=60XMB2O+,_,5KF* M!0)-$B,28'#H2.C][?O>ZP9`@*0B2O+41DD19*/[];NO[N1/K'_<4[(XN?&F M07K@99-I''6RQ(O2&<^\CA_/%D<3+QKS+SQ;Z*JJPS^6YABJ92\T6S6=A:\% MFN:9&@]4W>S:9NM/[&O*DY[BA9ZNP:^_Q6G64WPORKQA)^(9#%W&,0SMYVFR MGR;^?A:-6S#ZV<O\";OA2=I3M(Y1CF3W<]Y3+D]^_OKI\++5>O>.E2BQ=^]: M+XO]W[T93SL?XBR+9U-^?Y!FG,.3KP/FJ*;FFJKF+E355NW6,=,Z`+6C=_0N M4_5]U=E73:8;/4/K:=9?5:VGJHS8<E"Q@_U597MJZP-[63J.6CX[X\F8LVJK M7LGQX?4TC/*[/;UCL3#*XK634"SA"KZK3#!TS;)T8P%X`!,^,L=56V=;K_M< M2;6UM^5?J]7Z_>U,73<TS0)9(8)+LG(+65E,,WIJMZ<9?U!9E6A-XAE_&"E' MM53+,/3NPK)-W7G"8LLTU87IV(X+,C>=KFV`U)\!Y)D*L-W.6E>SD';#LERA M"YI9J8$.TH=_[3^H&FQK"X]986FZVM6,A1#T1R8X]Q@SKZ_\X69NP5-3[9IH MK4*T-E/5GM7MF>X?5+3CA(\/KI/8FVQ0;%W5NI8&1JUUG4?-UPR(8J`(&@CG M<?,UPUG8IFOKCYQO:#!?TVT+YL?)O[VH,TK"(7#CP+L+T\WKNIJ]L'65UFUG MW:#<NF["8D?M/F6Q85I`H>:8L/B:9QF/PO1@'.6=.!FO70'$`8V@`<CS&R\* MDOB&']SX'?\FSSK^K^L7.9H&.&J.]@0<===R8;'I.&",XKFM]ZT!^0_8I6%U MS6([89=V89<.VJ7A](P_JLO=BO-@FX9+^FEVT?L.)UX"2X?A>!Y'`8+O>/G: M9::.MJ?9MKW-,E?5P93`*9JHT+?A='I_$/!A"):X5J%IA67""M-UMR?.-;JJ ML=#`H6!F()Y;ZF8=R`_735LW#,>PY79"-YU"-[M,@X"A]C1MHVYJVH]2SO.K MTR\]IG?4#@2Q/7;J77-0Q3C@*1MZ*0^8EV7@3/,,AO=C=A-Z+)MP-O?&W/?\ M"6^S47C'TS;SI]R+\GG:`:``)[QC*>H!&^9C`,A&Z7Z4P4>:SWG2\7N]N9>D M?!#/LS".TIU==CL)H12[]5(P@CP-0>E]QEC"9W$>92E0SD9>.(5I/)(8)%F( MB]G$`RPCQJ,LN<>M]GGF[X]28!X,!P0&%XCWZ9S[X2@$PG`LFJ;OF,!!X'TX MGP/.*=1H;.;Y20R?X]!G.7)BB0KB4&="6,FAFWB:S\08;<GOYK`[\Z93VFG" MIT`X&^613Q2S\W_$T],XWMEMTU>0FOQ5X(RC1\#4A,8%>F?@]9D?S^^3<#S) M&-"8\1D0QD9)/&-!$D)Q"W@"7[QIF'K$'B@W4Y!6@=<L#O(I9R!@/PF)<K93 MR66WPZXF80ID7X,&(.)U:`*$A#@*,P;+XX@S\&,<,<>Q%#DUQ*B6@"_()B#$ M%":.(-(E$9\*2K[.`\"]Y)[0,M2+F3<?)'DT@!TS4`O@\&V<7.,^PYA@>=.2 M14NZ22I+S!/S1C$P.YP"$3@4A`GWP7A"+O6S/YM/)>=0XYN`4&SQ+2@AR:]N M`H#1F`RAU"PT!D;60)O!!-"74O)1G,P`YQN@<C8K%0`XFMWW"`1H71`P9,,` M=QJ$8XZ4(RADIM0<>@_4!X-I[%_S0,Y%='=V"0Y;5D>AH7YG>0?.`U!C::B@ M1@$JA0",@\D`/'T!4>H;A2XO"$"$*=B.YW,P%YYX0H<W,IGM>#&X`G^W3?M' M\2W[=PY*,/%`?P6E\+X@_Y)'8'`]203^\2@8#//1B">"9*+52^\C'QBS]UZ` M6)DDWK>7X%1,I1E#9!U`$'\%G.57*XN1/#$#I5RNK2T6;SHE-;=)N*S:Q(E> MKS']8<U^NFX+%&;H*.)A&D_Y)E1F:5;#GB*I93TS&*J>VGK//GQ<-"U[H;D. M%DZ::JB8%:KP!QG*T-,"U7;]KMGU_<!:+?=6X,B0VM4<*$6,A6$ZNE/?$F+A M'!5V_:9=R&],;>0[7<\)'-/3[<V;+D%:V=:&U+^V+7YT)FNVU(U%=Q1T3</G M]DC5K)$UW+REA-+8SH:<5FYW'/LY>BZRP7W2@_L4PH!<FMUEZZC6%HZEVMQ1 M1SJWA\'06(/"(R!7:)FJZBXL%ZAJR)MT;!T*.@YZ("XMX+;A`1\>D+:`TN"" MU=7UAGI)/[=F/\U<#/W`&'5MW^X&JN\Z^N;]"C!+&[HJ5J&JV=A0&,>G>+R. M1'L1C.R1ZVG`;#XRG)&Y><L*4(.IIN$:>GW3,PA2*(]U9#J+$?>UH:59FAFH MQG`U?UP%4V;!AFY!6JK;KJK5=YR-LO5<=1<&'ZF^-M)&H-3.@U(40)JJK)E& M@Z=%[K1F/T-;C`S;XB-3`V%ZAM-]@*4EG`9]%M3:=GU+F>^LLU9SX7&;J^I0 M-;BGZMVNNWG'`DQC0PUJ?)-.$G[?IO"(X07->K4:>;Q98\/<-+H+4]/!VV"9 MHNO-*D7=W-FR?E214B2+$/=DI9)P2%A2CE%+^*`+MI?<TK\0A3X_@NU/B&U] MW729U1(H]%K*'OL`Q0W4/YCP8CV#"2/DN;)HD84%1&68V8\@'8:LC_E$/^3( M109*6689['<P']U=EX:V%+8I$WUT%HHPUB6B'=+5%<\D5?.)KF]5$S>ZOE+Q M'%<7O1M-M;;0/+W+]K3_O.H)3]U0O14BGZ!IQ[K+--`WE^G=UK?6L\MSTHBJ M0O^&&OD2);KR(A6Z\L@"77FI^EQY9GFNK%;GRK.+<^79M;GR_-)<>8'*7'EJ M\:*\4%VN/+LL5UZF*E<V%>7*$VMRY45*<N6!BEQ9+L@5Y7<*<>7A0EQ1UA?@ MBBRAE37UMUS3K+M7EQ1UJ_(B1;?R])I;>7+)O1QTB]R\$7.WROPW1]QFYE\$ M7,S\Q5T%RZG.,#6SIUL/G95H/SC<XAT=<OD?F:A--L38@JRGA-@N1EC\./G7 MU>7AX.CTT^'/7]@[MG>,/?'!/TXNO_0OSM]]>R6B[[=7-7$)N3:$M4WMNUE6 MR[6OK=N:IKJ&L3`<J'Y)4DX],]+5A^Z36#K;ZQH_1%:%+T)ONKT_PD[;!B_4 MV;8C6'C,YW8$"S@UC\0>VQ)<7EVU!"O?]%A?M.J&1+/[D:WMIB=:XWG:@NL8 M#IM(@4BHJ*).RP:K$PKZ%)LS##0Z^F1O'I`9D"&>8<RP!P>$8#*$E..D6LF4 MMHY-LF7ZQ*P+$L*;.`P>THDT2W(_8_+%!%ZP-\-)&T]A63[/8O1"NZUCS;01 MLG@4&%?:`6B"($!H[("2#4BD(,VMVP*E60#.`VB61M#H`="6*`/S"Z9%/K%) MC5F(M>4O.4@\@-"49_$,B86,YAZ!NP*X6W$!J6DJM*2<\'V#GT"F[JA4;M!# M491L.-E[/R0\0`#O'L#J+2SN$O?%8YE'M,4:#K$#BG,E8T1^C%XDX#>AS['Z MT47YHPN0IR#W*([V@*UA@,EA)?SVB@;C?B(]+K?$'^"3(H1L,ATA6_``R$7> MUUYG^*+>@8PYRY.(^?`RDT:'\RB71LB"*2F"\](T]D.8%@CRRC24F#5)XBC. MTRF4VX"(PRPP!56#AR1Q+7D75Q=_VT2D('!X3U4'&@7LA\#J7)V-,@#MQTG` M=@1)7@8OH)(`-8'U6%+$X`ZFX36?4GTV`Q>2W%.R2TPJ.0K%GA=&05$]_,J3 M&-P.E"5YVA;L"+$X3*'N[.]?(.0END%EB4G\!@K$<-3$#29'<282]J!$<1ZC M$B/H<`90;SFES.0[O3`C[(!S4.W`R)"38$2-`\,<IT,P9$%,FR&7@/6&*KR0 M*MW0)2?YJNB(T]SWT791R'L\2:(81^%+G-!*2ZS$1\VX2"S2M$B[W^!GFZVS M-D/M"BCX$/DL^7GV)@K;X(:`?8,H!,LR=+1'>(`9J.@VP6^88)_[;^`#$+^( M0%QYA*$R8'\^/KPZ7-(<(GS(67&$`5/B1*SCD9_<ST%)._1['SY!'#M1N/<> MKT)#4L,.KP8$[_5K]A..XQZ#*8]VV6_H(/;?L/Y($`HR*N&UP8*C>^81#V60 M0:UBYU=F1VQ$.YWWH_BD6`3[[DJP"C`:,["3PZ.CDR]O:6@<@V1A?!#G&8U\ MEP@<5821O@.KN3<#T8'<A3LE3:B.<)H85``(!=HM$;K0B/,5#Z5S($DB-M\Q MILF@9I#S7(:PY$[D"IAF,9`AXO`3(G$(`BNVEY)'APOB5_@TY8W1O?>#_OG) MCAB2BK.+FF((E:*',@.+@NE8KX-]#81][5R>'!ZWF81&BTP*1^+19#2\-=!3 M&J:);_WL#B!""2QRIQ0J4W\R@%&)"R@N[BK`.@*L4X'-H]E@&;3+#)@!<5`7 MK,@CX7QV?IK&\74^IUU*A6RS0@6K;ZB,6"PJ_9_/+RY/!D>'7T[:3&VS\Z^? M/M$70&Z7%.O8L(2$+*/":)YG@P9670J"XM%XW</7.B'=->%1>Z7`KX=9O03% M!>@N9"P.)1;B03Y(QDOT9L)^T)^C>QR&&8`'[V.YA*!X%($6<S$(LF,>0<H] M?3@/+WHHRREFBG!U`5>GS($<EH0S(#B#)3C5IN^0M99KBK6D)84G[-6K]#;9 MZRGF`41C&?G)(H]M#0ARZM65;#HUZZNMSI(?J+`:9\E0#9MXB533=%/66.X6 M-99FLCWSA];#CVR]K50.F,J+`_)-J;SDQ%-.0US#:0:P*G:YI@IV`H\N>A$7 M+-Y^::_W[=&>SH4J&+$0#F`+7^9:8)^XTG;6^4C7=L&9]_%D63JR[?P7JSFO M&U]XM+H'0RMS'<H[Q&,5"P>]_K%+C@L>EG@@XX]=2G2/-3`0RB'@BPL#6_BN M9;.L8FG#,+>]<;'9-)LW+FS-A:=IJ`M==S6-C-.TMVF`_*A#26S?>G1V`@DK MU(*8:P#7,.><>9%HZJ.6R9N]DBXL]JC+2XX^NH<DEZXZ9A/(>&4*[)5)'24V MI5$+:\9[)QNLN6+>4^S9M$VH12B[A.CRP<,3&$`NA6QJ/A<I.]"&%$UX4B>@ MCGY$`#8DIM@OQ3SLP]>?!Q?G5=+Y4Y5T+A8U,VDHH6RB-S1PJWL@F]6O=@_$ MQ@OTNJ-K"],U7(MTK]NMZY[;4YV-NF?@H9W]@YIO_S^N,,IKL\\]*JG`@*XE M\3S!(OK1QR(?F;BHL\$LI%"?U+`2>?5R:^,WPON[()(V&$`:E178[,L(%68% MG?(%5-5X]A^FLP[X80T3IF_XQ8(X*>HOKU9_]<^/3_XU./STZ>+H\*I_<8ZQ M$F,GZ,E9FGU.XHS[LGQZ*R`Y$B25C?1%EU],:U-3:%46,@-<CN@W85G)RN$; MW+2ON2ZS[-;^FS=5/EHH`(@S'F8>>$6OOA:B#/@H_"\*R''$U#(KU!/A',@] M>PHH'$6B<F6$`&6CH[%(_$>\E9[C;WI!G63E:Q22%N&OHB6T=.L"8RXZ..FT M=LN5Z(!Z"GR,(<^"=32(OKX`"#)-/!!$DK(=M0$"H5P()N!^\F['P]RH(U:= MA@_O2S+;`@MQ.G5091.R7Y4R#`)<MDVP084LK#HM"&<9+LU!5@N,"O9W)`'] M)K/$M+#L?\F+!B$%`*KY10U<-,$@'@"8,,(&&E;K"1]!_(A\)#Z/L@Z[`"C) M;8A=(X]%_+;.H5"X,I^Z:K(C51Q\_TJ-4#K;CK`-^K"38=2<FDY%_XA:1;)A M5A$G@('?D\0)'`1"><(+ILB>$<ZH(;NB67*X["QUV!%E"Z*;AD`0'`2'7-9% M_2^#D\O+PGT"N"0'ON#TPN_2-0O!"W%O`KM3PD>&U&`3=@<SJ`7X^>I20$3< M]UMU.VXX[0VV?W@%,*[^Y_/)%S(KS%)SU/M!!A!($W-#9V6\;OW64IKNXFVK M.@N&F?`3_1"@3GE\Y'4P!8VPV2QWW7L?HMS>TDOA%FES,4!6^(ZVK`9P<SF( M7PGR#9802)LE-6)G"7XZA(2\V+K-=LB/9[L-GTY)^4[*RU<KSKW-7D<>]H.H M!`#?6/6!@/,#D,#.WLGYQ=G)F2A;1)M+I>_[TL+0GD#3068\G8`F5SHOMRCZ MGJ+%F=%)#652N*FD!Z^<L->L/S@_^:?HJ8FM'C*+4LKDTT&R$<X9@!W*"6+\ M>YD97E'Z1\E>U9Z]YGR.'FSHK5:AS$O`T`-Y?<6;IC'!2?$*'#JAM$@TR>8@ MD:0N+]Z6*6@6&39FG#7X!$;N@77C+6)6))C(%J!>L"&<YYDD1*A$)9?^A21/ M2@QU]3M(YMB&7,]H]6U7Q>I.WDL@8]NIU.=5/PKX7?TBEDB#7U%#47GUY]/^ MIY/!^>'928>=8WJ,>1D/.J^PP.R*4QOQ0-00+E1DR,N]]]Y`-%I>EUT7+/=< MRDG$XU%+H.HS;*8;;OT(:T45(&23<BT'9&G!Y$DPF:O"<3U4-\9Q2&D"D<HK M7>AC775YCK&28%;PUCI=<8UJ*&(<8"0*,7&V44%=$QSK"V4IW'D4VB"'M,U` M%*+-AE/2:AO)RSA!0.5!)LV+81YDNG4Z5BB0QQK@B^C:J%A`6'$,+AX2%O*I M.)O"!5X*QH3Y?UK%S")_0DH$2@5M_]UC_T3[$VA3(QV`53?ZR@A42N>_<-EA MCQ6^9P(;]0>0LGY$)-NP'N-\%4AAH6!;6_@!6`U_X8`R`3HOXG24HT'"&<N4 M`HUI',OT".H6[]:[EZ'L11-:#%L$1UP5A+%X"I9$MT&^?"AM?O?M0X<VRMGI MU>#RY.CB\IB]F<'O6H\)$EA^!T'3S^ZJ"%B&`H(:\&$^WGEU@O>%D69JW.)> M3+W[R_2N\PH=M0R.N]4RBDE54703RG>A(BGH2_=7-=;DL&3(;A&-_HX9W"RD MI((R0\Q-TH;!"+4A/RNP&4ZO4TC'E%K\EH-OBTGR6D]]DAPL)^5A4)\``^7+ M<?/E>.EE-`VCZ_IK&BHGS/`0L3Z!ALH)_NH$OS;!6YW@R0G8LDCY+Y!)%.^K MD8*W7WBA<)31@#[C$2H#8Q<Y>W(#I3A/9B$UBM)E!L]@50-UA/.:_2\(\?3L M2O1#?[\92G%1)IFSW>4DH4@49Q0E&^=NWQ_7-RV3(.Q=+L&6Z<_;M0="RG?) MGM-0IK15MZ@,Y<_IK*IK^JIK,?E680^A%'8"D'$T*`[F92XASP^;53CVK986 MCJ;>.)4'F^M3AU/,BM@L1>%+.$O.O\@?L,U6#E*)@%<A2&]H"]*>8G(C#J;5 MG8(=F6`7,\F;M(4>PO>[=IDWL[^$NYURWF>Z[0YPYG&2L?LX9ZEW*_+5XK)Q MN7G,Q/_/`,G="_C-`9Y7I)UTA.VP5VTQK?1>0F1U,<I^G[)63>CHMSC\OERY M+-%A9]0(@W"'7@=2PE]R;TH.5*2:?ICA]0:QGC(=*IKF7C9)JZ-P*2"`(`\? MEHK-Y>$R0?^_[J[UIVTDB'^&OV*/BKM$UX0X`5)*B\0%.$4%$I'2NTJ<K(0X MQ2*Q(S]XW+7_^^W,[*YW'3MV4J%*_5)*LN^=F9W';P;Q(2QZZK2:=N3;M_.X MHI&"?7QU7$$Y:I,GH8HJ)^JL2"#"KW/I>W);Y-8A8DL3%6=ZM,@ZO8O^U>D` M8(KVQ?'@@R"V//J40?;RQ"@N=F,K(2D@-I/(5"-0"I*8O*0W06>J51'!+:4X MU2;!S:=)3C4Q:2]Y-`49;BPCODSJ(^2!N"H3/'`HSSW+GXV"(0==L:F6HA90 MYIJT<P9AH/:,\0(`2V5$#Y+#2UV-=B.JB7DUYHVH1IG"(/*9=@6%TB!3'&@W M5/I>T`KVI[6CVRE78)R`N/*([38.]LL<J11BVM&:5)]N(/3@L1L.1V"GC&-# M$HIEH"AB%7Z,L)9[]X^ZDH/IQ9;:8GEA0+,@&?*O^8LO6YR>E#F/V+OW_$<O MN4Q]WS,GNO,!4*1_'03QG-!/:-LNWPM%=3MG%6U8@LK8XDSXV_F>6=?LW3N: MPI"GEU=&QYB+Z(0)"UL"<^ZN0A2<R;BQX8V'P=B(Y,%HJE%E.^:O"U\Z?UC\ M"9^@SCI#3W<%$"P)^47F\F"JD/R>JS_N+08^Z#!A"FX&`9_))N&='W.3+(@] M=GMW/P[O)3TA!+EPY^)>I%+6ZU_V/@ZN^_WON"XD77E5K))]6>+3A8OX/8<7 MN"D3A;38@JFI)9]_,@EIFJ*U5EF-65*=6/:^@I9\V;GZW/^H6&:-YW@I@2GH MG/;6FO(=<3+%_/0#'_UD#S_YFV]`%DL2T*!_?#4X_?&:68C)G#_[#0UPETNN M!X41^%_#R'ZX5<I6SL&[`3]TYRD",P.0Z^IDP<VEO0UDC27#UEE7>KL2K0$E M>IU]AI-;%.)%1@^X#N*YBLBC@5//,%C"J;._FVF"\(V#+!$R$$;.,6Z,(3:S MI'FZ4S)<VB@J,9C9I:JLG@R(KKBLM'R774M-E^Z4J`W:.?Z2;?E5$RY]'`80 MB-;)I9.E.2K"5Z!'FB'VR#K5U65M.E(;)UK81!L(<)2!/^)JYS-F8COXZ]29 MZ:W09QL\RQ@[P=J!=%03U-2D;L_5%'?RG*NZ,YUO-;$!WN(L,T`0]+?$MT/T M*S(Q=%0J=DOY[G7'ES\'7^7U^;ERPDT6/UH:_[C1D(>+H&_IJD2?=Z9I?W3$ M#A)D8D;[;&JD;C<J;H;>B3`.G'1`8.P[H?=;)'W;$LDYA&!^)#`!.$+ZE&2D MZTLP'&E^W(T<R"13?DG1Q@MLDFZPD9J%BP7D<]J_!PZSPURLH.=6%]S7)[XG M:$!$U=##;<*F\4X@0K>9**3=GG`@PI3\\]57DX&ZSA/O%$9'QM1BZ-LN`"FF MC@K0(+5OI<X^_9)F/:#4<=L%GSTDD^C/W1+?%^3WVZ/AV`B_BF/$@#FP%&!N M(-FKR=K*DR2EID+7HKS<`5\9,7F*[@C0AV$>?XI;=:.ZF0^B4PB0B%1D()SZ M"<,'.;16391W@\H:FDZ?1:""J[G8T#%_6$@HA?A;H4)1/MY/JU`DT7Z-K_O- M/5G`?7<5&'B#U=Z\)`H<$'#.(](7(KNIDE(.Z`UWM@[D[8`0VX!L%L"N,PC] MI)(_@4S@5CE-%B1"I9*@(.IM-2A7$7^LF370M#"!KMD4"73=":-<'4`CR<Q< MUWOPH5A&1NKMU"?X#PU.)3K<\!YP3`B0<CBY]O\4X415/R7`#V6&*.!ZY!!U MUH-0)Z2]@78H<CL=#"A+I,[<#Z,:.IY!FY^X3S%_JR"_#$2]G@J7#$NIT2/' M09P0?SGYDSF#\*EJ\$6L5"T*0J@P8[)Z7#G89Q)F,N;BF7!4S(\#(SL1=Y"1 MF9I._P3Q)Q)34Y4,X)_Z78I;Z<-RQ?'RV56,(OBU8;4M0)=#G7_ZXQB[UBK\ M:KTPOSI/8"N1EI.7F$/@52CNE\/'M.5U&'D?$P$P<Z'+_VU+?A7LB%5E%E)[ ML)B/'0J]R>Q1G!1TN%(/)*%U>HUF<Z7:F5U1YBQT$1\">F8?TA^Z;8#TE.L[ M=@/1%;,\NNU6Z:[.;!X]ZY.W(1E#9Q51V2?%*RO5ILMGEE1M.IGDU-AO6U3< MC3]W*]3\:+\<E'VA%%5AY:F%LE.(9%^Y]%16W2F%B5\H#OU]!9Y$=2<<7JOP M5%#4*:^BDRH)4::JTP=&!0ES1(P@E'5R1BPM!RR-7,&E&)7P@%WX-V_9=LA5 M8OXA*`/-)A4?:%+Q`17'X<</9AVD(!N_@VU._\7<J";E=C7W@"_!X"0,)O0` M^?(O/S![%D\C=SYUG0#3KRD_M5&P\E05O\RU6V\:F#LI?H*Z_T_]QD-H']2X MQ^_HYT7OY/K\U#XY'72NNGT`]%>V`($#119W6O4G23\UUE$45KFM,OAK(S5@ M)G;L19P`CJ?1D),WIQ?_82N5&J-JG)GR9+7RFOD"Q2RO":5IH*KGP=>]-WLM MRLRR6BL(E%:+U9I[+R125B\49U:$0_Y:J2K<0DFX#XSJCN9PG3S-M=)2^/NU M!PD>>ZS50FL0M+D39X*P;XB("->*(S`BB`J4>J4.<C.0[3N;8)&.G0F7B?$, M3+W+3_;@SG\<8/',,R@Z\QJT<NNM1,!364U1C\;5\M[YN\D/`:U)/DB'VWD# MQPNY:'MPY!`?H:(&60EHT[`A%8_@&JQH2:6Y-D1T2Y3@P![406RHWQMT_Z8Q M0&6H:UU4;@'60B#;UQA>#*IUT1;$Q_^K>RFP[30V[.B;?H0VGO"ANH4+)#<N M+!#ZJ>@*UKD"^>C%24*ZFU=CO%_>L'=NGUT.*C!Q%1UQ-PD6$LO]@4D&X[UZ M!6TJ:51C%7K\1SX\_C_I7$#(.R>>"K\PZOF:_0K"N"K13(>\]3?5SYP32^Z( M;>7.:TP+D/J"Z<K,AX=6;D:9.U8X)]XF.YVY40*5%</RWN!B3"X'[D;=28I; AJLDW!@M4D[]'B-CV,)Z];XX.1K<'0VOS?]87H6TU<0`` ` end - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Jul 15 2002 - 22:00:13 EST