Commit 6e3ea49e authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: Make ntfs_lookup() NFS export safe, i.e. use d_splice_alias(), etc.

parent a940d783
......@@ -23,6 +23,7 @@ ToDo:
2.1.7 - WIP
- Set i_generation in the VFS inode from the seq_no of the NTFS inode.
- Make ntfs_lookup() NFS export safe, i.e. use d_splice_alias(), etc.
2.1.6 - Fix minor bug in handling of compressed directories.
......
......@@ -2,7 +2,7 @@
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......
......@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
......@@ -41,16 +41,17 @@
* @dir_ino looking for the converted Unicode name. If the name is found in the
* directory, the corresponding inode is loaded by calling ntfs_iget() on its
* inode number and the inode is associated with the dentry @dent via a call to
* d_add().
* d_splice_alias().
*
* If the name is not found in the directory, a NULL inode is inserted into the
* dentry @dent. The dentry is then termed a negative dentry.
* dentry @dent via a call to d_add(). The dentry is then termed a negative
* dentry.
*
* Only if an actual error occurs, do we return an error via ERR_PTR().
*
* In order to handle the case insensitivity issues of NTFS with regards to the
* dcache and the dcache requiring only one dentry per directory, we deal with
* dentry aliases that only differ in case in ->ntfs_lookup() while maintining
* dentry aliases that only differ in case in ->ntfs_lookup() while maintaining
* a case sensitive dcache. This means that we get the full benefit of dcache
* speed when the file/directory is looked up with the same case as returned by
* ->ntfs_readdir() but that a lookup for any other case (or for the short file
......@@ -70,15 +71,18 @@
* 1) @dent perfectly matches (i.e. including case) a directory entry with a
* file name in the WIN32 or POSIX namespaces. In this case
* ntfs_lookup_inode_by_name() will return with name set to NULL and we
* just d_add() @dent.
* just d_splice_alias() @dent.
* 2) @dent matches (not including case) a directory entry with a file name in
* the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
* with name set to point to a kmalloc()ed ntfs_name structure containing
* the properly cased little endian Unicode name. We convert the name to the
* current NLS code page, search if a dentry with this name already exists
* and if so return that instead of @dent. The VFS will then destroy the old
* @dent and use the one we returned. If a dentry is not found, we allocate
* a new one, d_add() it, and return it as above.
* and if so return that instead of @dent. At this point things are
* complicated by the possibility of 'disconnected' dentries due to NFS
* which we deal with appropriately (see the code comments). The VFS will
* then destroy the old @dent and use the one we returned. If a dentry is
* not found, we allocate a new one, d_splice_alias() it, and return it as
* above.
* 3) @dent matches either perfectly or not (i.e. we don't care about case) a
* directory entry with a file name in the DOS namespace. In this case
* ntfs_lookup_inode_by_name() will return with name set to point to a
......@@ -120,7 +124,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
dent_ino == FILE_MFT) {
/* Perfect WIN32/POSIX match. -- Case 1. */
if (!name) {
d_add(dent, dent_inode);
d_splice_alias(dent_inode, dent);
ntfs_debug("Done.");
return NULL;
}
......@@ -132,7 +136,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
}
ntfs_error(vol->sb, "Found stale reference to inode "
"0x%lx (reference sequence number = "
"0x%x, inode sequence number = 0x%x, "
"0x%x, inode sequence number = 0x%x), "
"returning -EIO. Run chkdsk.",
dent_ino, MSEQNO(mref),
NTFS_I(dent_inode)->seq_no);
......@@ -162,7 +166,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
{
struct dentry *real_dent;
struct dentry *real_dent, *new_dent;
MFT_RECORD *m;
attr_search_context *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
......@@ -173,8 +177,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
if (name->type != FILE_NAME_DOS) { /* Case 2. */
nls_name.len = (unsigned)ntfs_ucstonls(vol,
(uchar_t*)&name->name, name->len,
(unsigned char**)&nls_name.name,
name->len * 3 + 1);
(unsigned char**)&nls_name.name, 0);
kfree(name);
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
FILE_NAME_ATTR *fn;
......@@ -225,8 +228,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
/* Convert the found WIN32 name to current NLS code page. */
nls_name.len = (unsigned)ntfs_ucstonls(vol,
(uchar_t*)&fn->file_name, fn->file_name_length,
(unsigned char**)&nls_name.name,
fn->file_name_length * 3 + 1);
(unsigned char**)&nls_name.name, 0);
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
......@@ -256,7 +258,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
err = -ENOMEM;
goto err_out;
}
d_add(real_dent, dent_inode);
d_splice_alias(dent_inode, real_dent);
return real_dent;
}
kfree(nls_name.name);
......@@ -266,14 +268,54 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
/*
* Already have the inode and the dentry attached, decrement
* the reference count to balance the ntfs_iget() we did
* earlier on.
* earlier on. We found the dentry using d_lookup() so it
* cannot be disconnected and thus we do not need to worry
* about any NFS/disconnectedness issues here.
*/
iput(dent_inode);
return real_dent;
}
/* Negative dentry: instantiate it. */
d_instantiate(real_dent, dent_inode);
return real_dent;
/*
* Negative dentry: instantiate it unless the inode is a directory and
* has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
* in which case d_move() that in place of the found dentry.
*/
if (!S_ISDIR(dent_inode)) {
/* Not a directory; everything is easy. */
d_instantiate(real_dent, dent_inode);
return real_dent;
}
spin_lock(&dcache_lock);
if (list_empty(&dent_inode->i_dentry)) {
/*
* Directory without a 'disconnected' dentry; we need to do
* d_instantiate() by hand because it takes dcache_lock which
* we already hold.
*/
list_add(&real_dent->d_alias, &dent_inode->i_dentry);
real_dent->d_inode = dent_inode;
spin_unlock(&dcache_lock);
security_d_instantiate(real_dent, dent_inode);
return real_dent;
}
/*
* Directory with a 'disconnected' dentry; get a reference to the
* 'disconnected' dentry.
*/
new_dent = list_entry(dent_inode->i_dentry.next, struct dentry,
d_alias);
__dget_locked(new_dent);
spin_unlock(&dcache_lock);
/* Do security vodoo. */
security_d_instantiate(real_dent, dent_inode);
/* Move new_dent in place of real_dent. */
d_move(new_dent, real_dent);
/* Balance the ntfs_iget() we did above. */
iput(dent_inode);
/* Throw away real_dent. */
dput(real_dent);
/* Use new_dent as the actual dentry. */
return new_dent;
eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
......
/*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
......@@ -305,8 +305,9 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
* Convert the input little endian, 2-byte Unicode string @ins, of length
* @ins_len into the string format dictated by the loaded NLS.
*
* If @outs is NULL, this function allocates the string and the caller is
* responsible for calling kfree(@outs); when finished with it.
* If *@outs is NULL, this function allocates the string and the caller is
* responsible for calling kfree(*@outs); when finished with it. In this case
* @outs_len is ignored and can be 0.
*
* On success the function returns the number of bytes written to the output
* string *@outs (>= 0), not counting the terminating NULL byte. If the output
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment