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 ...@@ -272,6 +272,8 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/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: 2.1.6:
- Fix minor bug in handling of compressed directories that fixes the - Fix minor bug in handling of compressed directories that fixes the
erroneous "du" and "stat" output people reported. erroneous "du" and "stat" output people reported.
......
ToDo: ToDo:
- Find and fix bugs. - Find and fix bugs.
- Enable NFS exporting of NTFS.
- Implement aops->set_page_dirty() in order to take control of buffer - Implement aops->set_page_dirty() in order to take control of buffer
dirtying. Not having it means if page_has_buffers(), all buffers 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 will be dirtied with the page. And if not they won't be. That is
...@@ -20,10 +19,19 @@ ToDo: ...@@ -20,10 +19,19 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure sufficient for synchronisation here. We then just need to make sure
ntfs_readpage/writepage/truncate interoperate properly with us. 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. - 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. - 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. 2.1.6 - Fix minor bug in handling of compressed directories.
......
...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o ...@@ -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 \ 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 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) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
/** /**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. * 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 * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * 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, ...@@ -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 " "and if that doesn't find any "
"errors please report you saw " "errors please report you saw "
"this message to " "this message to "
"linux-ntfs-dev@lists.sf.net."); "linux-ntfs-dev@lists."
"sourceforge.net.");
goto dir_err_out; goto dir_err_out;
} }
...@@ -457,7 +458,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -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 " "and if that doesn't find any "
"errors please report you saw " "errors please report you saw "
"this message to " "this message to "
"linux-ntfs-dev@lists.sf.net."); "linux-ntfs-dev@lists."
"sourceforge.net.");
ntfs_unmap_page(page); ntfs_unmap_page(page);
goto dir_err_out; goto dir_err_out;
} }
......
...@@ -196,7 +196,7 @@ struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no) ...@@ -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 * 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) { if (err == -ENOMEM) {
iput(vi); iput(vi);
...@@ -1137,7 +1137,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *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 " "the attribute is resident (mft_no "
"0x%lx, type 0x%x, name_len %i). " "0x%lx, type 0x%x, name_len %i). "
"Please report you saw this message " "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); vi->i_ino, ni->type, ni->name_len);
goto unm_err_out; goto unm_err_out;
} }
...@@ -1157,8 +1158,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1157,8 +1158,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). " "type 0x%x, name_len %i). "
"Please report you saw this " "Please report you saw this "
"message to linux-ntfs-dev@" "message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino, "lists.sourceforge.net",
ni->type, ni->name_len); vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out; goto unm_err_out;
} }
NInoSetCompressed(ni); NInoSetCompressed(ni);
...@@ -1169,7 +1171,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -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, " "(mft_no 0x%lx, type 0x%x, "
"name_len %i). Please report " "name_len %i). Please report "
"you saw this message to " "you saw this message to "
"linux-ntfs-dev@lists.sf.net", "linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type, vi->i_ino, ni->type,
ni->name_len); ni->name_len);
goto unm_err_out; goto unm_err_out;
...@@ -1224,8 +1227,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1224,8 +1227,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). " "type 0x%x, name_len %i). "
"Please report you saw this " "Please report you saw this "
"message to linux-ntfs-dev@" "message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino, "lists.sourceforge.net",
ni->type, ni->name_len); vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out; goto unm_err_out;
} }
NInoSetEncrypted(ni); NInoSetEncrypted(ni);
...@@ -1238,8 +1242,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1238,8 +1242,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). " "type 0x%x, name_len %i). "
"Please report you saw this " "Please report you saw this "
"message to linux-ntfs-dev@" "message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino, "lists.sourceforge.net",
ni->type, ni->name_len); vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out; goto unm_err_out;
} }
NInoSetSparse(ni); NInoSetSparse(ni);
...@@ -1541,7 +1546,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1541,7 +1546,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"of $MFT is not in the base " "of $MFT is not in the base "
"mft record. Please report " "mft record. Please report "
"you saw this message to " "you saw this message to "
"linux-ntfs-dev@lists.sf.net"); "linux-ntfs-dev@lists."
"sourceforge.net");
goto put_err_out; goto put_err_out;
} else { } else {
/* Sequence numbers must match. */ /* Sequence numbers must match. */
...@@ -1662,7 +1668,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1662,7 +1668,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"Run chkdsk and if no errors " "Run chkdsk and if no errors "
"are found, please report you " "are found, please report you "
"saw this message to " "saw this message to "
"linux-ntfs-dev@lists.sf.net"); "linux-ntfs-dev@lists."
"sourceforge.net");
put_attr_search_ctx(ctx); put_attr_search_ctx(ctx);
/* Revert to the safe super operations. */ /* Revert to the safe super operations. */
sb->s_op = &ntfs_mount_sops; sb->s_op = &ntfs_mount_sops;
......
...@@ -331,10 +331,133 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st ...@@ -331,10 +331,133 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
} }
} }
/* /**
* Inode operations for directories. * Inode operations for directories.
*/ */
struct inode_operations ntfs_dir_inode_ops = { struct inode_operations ntfs_dir_inode_ops = {
.lookup = ntfs_lookup, /* VFS: Lookup directory. */ .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. * 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 * Copyright (c) 2001,2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
...@@ -1338,6 +1338,40 @@ struct super_operations ntfs_sops = { ...@@ -1338,6 +1338,40 @@ struct super_operations ntfs_sops = {
.show_options = ntfs_show_options, /* Show mount options in proc. */ .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 * ntfs_fill_super - mount an ntfs files system
* @sb: super block of ntfs file system to mount * @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) ...@@ -1544,6 +1578,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
default_upcase = NULL; default_upcase = NULL;
} }
up(&ntfs_lock); up(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops;
return 0; return 0;
} }
ntfs_error(sb, "Failed to allocate root directory."); ntfs_error(sb, "Failed to allocate root directory.");
...@@ -1788,13 +1823,13 @@ static void __exit exit_ntfs_fs(void) ...@@ -1788,13 +1823,13 @@ static void __exit exit_ntfs_fs(void)
printk(KERN_CRIT "NTFS: This causes memory to leak! There is " printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
"probably a BUG in the driver! Please report " "probably a BUG in the driver! Please report "
"you saw this message to " "you saw this message to "
"linux-ntfs-dev@lists.sf.net\n"); "linux-ntfs-dev@lists.sourceforge.net\n");
/* Unregister the ntfs sysctls. */ /* Unregister the ntfs sysctls. */
ntfs_sysctl(0); ntfs_sysctl(0);
} }
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); 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"); MODULE_LICENSE("GPL");
#ifdef DEBUG #ifdef DEBUG
MODULE_PARM(debug_msgs, "i"); 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