Commit 7a5c468d authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: Release 2.1.7 - Enable NFS exporting of mounted NTFS volumes.

- Implement ntfs_get_parent() and ntfs_get_dentry() as the NTFS specific
  export operations ->get_parent() and ->get_dentry() respectively.
parent ad71d86a
......@@ -272,6 +272,8 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.7:
- Enable NFS exporting of mounted NTFS volumes.
2.1.6:
- Fix minor bug in handling of compressed directories that fixes the
erroneous "du" and "stat" output people reported.
......
ToDo:
- Find and fix bugs.
- Enable NFS exporting of NTFS.
- Implement aops->set_page_dirty() in order to take control of buffer
dirtying. Not having it means if page_has_buffers(), all buffers
will be dirtied with the page. And if not they won't be. That is
......@@ -20,10 +19,19 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure
ntfs_readpage/writepage/truncate interoperate properly with us.
2.1.7 - WIP
2.1.7 - Enable NFS exporting of mounted NTFS volumes.
- 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.
- Implement ->get_dentry() in fs/ntfs/namei.c::ntfs_get_dentry() as the
default doesn't allow inode number 0 which is a valid inode on NTFS
and even if it did allow that it uses iget() instead of ntfs_iget()
which makes it useless for us.
- Implement ->get_parent() in fs/ntfs/namei.c::ntfs_get_parent() as the
default just returns -EACCES which is not very useful.
- Define export operations (->s_export_op) for NTFS (ntfs_export_ops)
and set them up in the super block at mount time (super.c) this
allows mounted NTFS volumes to be exported via NFS.
2.1.6 - Fix minor bug in handling of compressed directories.
......
......@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
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.1.7-WIP\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.7\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
/**
* dir.c - NTFS kernel directory operations. 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
......@@ -200,7 +200,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"and if that doesn't find any "
"errors please report you saw "
"this message to "
"linux-ntfs-dev@lists.sf.net.");
"linux-ntfs-dev@lists."
"sourceforge.net.");
goto dir_err_out;
}
......@@ -457,7 +458,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"and if that doesn't find any "
"errors please report you saw "
"this message to "
"linux-ntfs-dev@lists.sf.net.");
"linux-ntfs-dev@lists."
"sourceforge.net.");
ntfs_unmap_page(page);
goto dir_err_out;
}
......
......@@ -196,7 +196,7 @@ struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no)
}
/*
* There is no point in keeping bad inodes around if the failure was
* due to ENOMEM. We want to be able to retry again layer.
* due to ENOMEM. We want to be able to retry again later.
*/
if (err == -ENOMEM) {
iput(vi);
......@@ -1137,7 +1137,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"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",
"to linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type, ni->name_len);
goto unm_err_out;
}
......@@ -1157,8 +1158,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"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);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetCompressed(ni);
......@@ -1169,7 +1171,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"(mft_no 0x%lx, type 0x%x, "
"name_len %i). Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net",
"linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
......@@ -1224,8 +1227,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"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);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetEncrypted(ni);
......@@ -1238,8 +1242,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"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);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetSparse(ni);
......@@ -1541,7 +1546,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"of $MFT is not in the base "
"mft record. Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net");
"linux-ntfs-dev@lists."
"sourceforge.net");
goto put_err_out;
} else {
/* Sequence numbers must match. */
......@@ -1662,7 +1668,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"Run chkdsk and if no errors "
"are found, please report you "
"saw this message to "
"linux-ntfs-dev@lists.sf.net");
"linux-ntfs-dev@lists."
"sourceforge.net");
put_attr_search_ctx(ctx);
/* Revert to the safe super operations. */
sb->s_op = &ntfs_mount_sops;
......
......@@ -331,10 +331,133 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
}
}
/*
/**
* Inode operations for directories.
*/
struct inode_operations ntfs_dir_inode_ops = {
.lookup = ntfs_lookup, /* VFS: Lookup directory. */
};
/**
* ntfs_get_parent - find the dentry of the parent of a given directory dentry
* @child_dent: dentry of the directory whose parent directory to find
*
* Find the dentry for the parent directory of the directory specified by the
* dentry @child_dent. This function is called from
* fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the
* default ->decode_fh() which is export_decode_fh() in the same file.
*
* The code is based on the ext3 ->get_parent() implementation found in
* fs/ext3/namei.c::ext3_get_parent().
*
* Note: ntfs_get_parent() is called with @child_dent->d_inode->i_sem down.
*
* Return the dentry of the parent directory on success or the error code on
* error (IS_ERR() is true).
*/
struct dentry *ntfs_get_parent(struct dentry *child_dent)
{
struct inode *vi = child_dent->d_inode;
ntfs_inode *ni = NTFS_I(vi);
MFT_RECORD *mrec;
attr_search_context *ctx;
ATTR_RECORD *attr;
FILE_NAME_ATTR *fn;
struct inode *parent_vi;
struct dentry *parent_dent;
unsigned long parent_ino;
ntfs_debug("Entering for inode %lu.", vi->i_ino);
/* Get the mft record of the inode belonging to the child dentry. */
mrec = map_mft_record(ni);
if (unlikely(IS_ERR(mrec)))
return (struct dentry *)mrec;
/* Find the first file name attribute in the mft record. */
ctx = get_attr_search_ctx(ni, mrec);
if (unlikely(!ctx)) {
unmap_mft_record(ni);
return ERR_PTR(-ENOMEM);
}
try_next:
if (unlikely(!lookup_attr(AT_FILE_NAME, NULL, 0, IGNORE_CASE, 0,
NULL, 0, ctx))) {
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
return ERR_PTR(-ENOENT);
}
attr = ctx->attr;
if (unlikely(attr->non_resident))
goto try_next;
fn = (FILE_NAME_ATTR *)((u8 *)attr +
le16_to_cpu(attr->data.resident.value_offset));
if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >=
(u8*)attr + le32_to_cpu(attr->length)))
goto try_next;
/* Get the inode number of the parent directory. */
parent_ino = MREF_LE(fn->parent_directory);
/* Release the search context and the mft record of the child. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
/* Get the inode of the parent directory. */
parent_vi = ntfs_iget(vi->i_sb, parent_ino);
if (unlikely(IS_ERR(parent_vi) || is_bad_inode(parent_vi))) {
if (!IS_ERR(parent_vi))
iput(parent_vi);
return ERR_PTR(-EACCES);
}
/* Finally get a dentry for the parent directory and return it. */
parent_dent = d_alloc_anon(parent_vi);
if (unlikely(!parent_dent)) {
iput(parent_vi);
return ERR_PTR(-ENOMEM);
}
ntfs_debug("Done for inode %lu.", vi->i_ino);
return parent_dent;
}
/**
* ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment
* @sb: super block identifying the mounted ntfs volume
* @fh: the file handle sub-fragment
*
* Find a dentry for the inode given a file handle sub-fragment. This function
* is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is
* called from the default ->decode_fh() which is export_decode_fh() in the
* same file. The code is closely based on the default ->get_dentry() helper
* fs/exportfs/expfs.c::get_object().
*
* The @fh contains two 32-bit unsigned values, the first one is the inode
* number and the second one is the inode generation.
*
* Return the dentry on success or the error code on error (IS_ERR() is true).
*/
struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
{
struct inode *vi;
struct dentry *dent;
unsigned long ino = ((u32 *)fh)[0];
u32 gen = ((u32 *)fh)[1];
ntfs_debug("Entering for inode %lu, generation %u.", ino, gen);
vi = ntfs_iget(sb, ino);
if (unlikely(IS_ERR(vi)))
return (struct dentry *)vi;
if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) {
/* We didn't find the right inode. */
ntfs_debug("Inode %lu, bad count: %d %d or version %u %u.",
vi->i_ino, vi->i_nlink,
atomic_read(&vi->i_count), vi->i_generation,
gen);
iput(vi);
return ERR_PTR(-ESTALE);
}
/* Now find a dentry. If possible, get a well-connected one. */
dent = d_alloc_anon(vi);
if (unlikely(!dent)) {
iput(vi);
return ERR_PTR(-ENOMEM);
}
ntfs_debug("Done for inode %lu, generation %u.", ino, gen);
return dent;
}
/*
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001,2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -1338,6 +1338,40 @@ struct super_operations ntfs_sops = {
.show_options = ntfs_show_options, /* Show mount options in proc. */
};
/**
* Declarations for NTFS specific export operations (fs/ntfs/namei.c).
*/
extern struct dentry *ntfs_get_parent(struct dentry *child_dent);
extern struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh);
/**
* Export operations allowing NFS exporting of mounted NTFS partitions.
*
* We use the default ->decode_fh() and ->encode_fh() for now. Note that they
* use 32 bits to store the inode number which is an unsigned long so on 64-bit
* architectures is usually 64 bits so it would all fail horribly on huge
* volumes. I guess we need to define our own encode and decode fh functions
* that store 64-bit inode numbers at some point but for now we will ignore the
* problem...
*
* We also use the default ->get_name() helper (used by ->decode_fh() via
* fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs
* independent.
*
* The default ->get_parent() just returns -EACCES so we have to provide our
* own and the default ->get_dentry() is incompatible with NTFS due to not
* allowing the inode number 0 which is used in NTFS for the system file $MFT
* and due to using iget() whereas NTFS needs ntfs_iget().
*/
static struct export_operations ntfs_export_ops = {
.get_parent = ntfs_get_parent, /* Find the parent of a given
directory. */
.get_dentry = ntfs_get_dentry, /* Find a dentry for the inode
given a file handle
sub-fragment. */
};
/**
* ntfs_fill_super - mount an ntfs files system
* @sb: super block of ntfs file system to mount
......@@ -1544,6 +1578,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
default_upcase = NULL;
}
up(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops;
return 0;
}
ntfs_error(sb, "Failed to allocate root directory.");
......@@ -1788,13 +1823,13 @@ static void __exit exit_ntfs_fs(void)
printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
"probably a BUG in the driver! Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net\n");
"linux-ntfs-dev@lists.sourceforge.net\n");
/* Unregister the ntfs sysctls. */
ntfs_sysctl(0);
}
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2003 Anton Altaparmakov");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2004 Anton Altaparmakov");
MODULE_LICENSE("GPL");
#ifdef DEBUG
MODULE_PARM(debug_msgs, "i");
......
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