Commit 3c51ba14 authored by Anton Altaparmakov's avatar Anton Altaparmakov

Integrate ntfs tng with kernel now that the old driver had been removed.

parent 7ff0cd43
NTFS Overview
=============
To mount an NTFS 1.2/3.x (Windows NT4/2000/XP) volume, use the filesystem
type 'ntfs'. The driver currently works only in read-only mode, with no
fault-tolerance supported.
For ftdisk support, limited success was reported with volume sets on top of
the md driver, although mirror and stripe sets should work as well - if the
md driver can be talked into using the same layout as Windows NT. However,
using the md driver will fail if any of your NTFS partitions have an odd
number of sectors.
Supported mount options
=======================
nls=name Character set to use when returning file names.
Unlike VFAT, NTFS suppresses names that contain
unconvertible characters. Note that most character
sets contain insufficient characters to represent all
possible Unicode characters that can exist on NTFS. To
be sure you are not missing any files, you are advised
to use nls=utf8 which is capable of representing all
Unicode characters.
uid=
gid=
umask= Provide default owner, group, and access mode mask.
These options work as documented in mount(8). By
default, the files are owned by root and are not
readable by anyone else.
fmask=
dmask= Instead of specifying umask which applies both to
files and directories, fmask applies only to files and
dmask only to directories.
sloppy=<BOOL> If sloppy is specified, ignore unknown mount options.
Otherwise the default behaviour is to abort mount if
any unknown options are found.
errors=opt What to do when critical file system errors are found.
Following values can be used for "opt":
continue: DEFAULT, try to clean-up as much as
possible, e.g. marking a corrupt inode as
bad so it is no longer accessed.
recover: At present only supported is recovery of
the boot sector from the backup copy. If a
read-only mount, the recovery is done in
memory only and not written to disk.
show_inodes=opt Allows choice of which types of inode names readdir()
returns, i.e. this affects what "ls" shows. Following
values can be used for "opt":
system: show system files
win32: long file names (includes POSIX) [DEFAULT]
long: same as win32
dos: short file names only (excludes POSIX)
short: same as dos
posix: same as both win32 and dos
all: all file names
Note that the options are additive, i.e. specifying:
show_inodes=system,show_inodes=win32,show_inodes=dos
is the same as specifying:
show_inodes=all
Note that the "posix" and "all" options will show all
directory names, BUT the link count on each directory
inode entry is set to 1, due to Linux not supporting
directory hard links. This may well confuse some
userspace applications, since the directory names will
have the same inode numbers. Thus it is NOT advisable
to use the "posix" and "all" options. We provide them
only for completeness sake.
Further, note that the "system" option will not show
"$MFT" due to bugs/mis-features in glibc. Even though
it does not show, you can specifically "ls" it:
ls -l \$MFT
And of course you can stat it, too.
Further, note that irrespective of what show_inodes
option(s) you use, all files are accessible when you
specify the correct name, even though they may not be
shown in a normal "ls", i.e. you can always access the
system files and both the short and long file names of
files and directories.
Finally, note that win32 and dos file names are not
case sensitive and can be accessed using any
combination of lower and upper case, while POSIX file
names are case sensitive and they can only be accessed
given the correct case.
mft_zone_multiplier= Set the MFT zone multiplier for the volume (this
setting is not persistent across mounts and can be
changed from mount to mount but cannot be changed on
remount). Values of 1 to 4 are allowed, 1 being the
default. The MFT zone multiplier determines how much
space is reserved for the MFT on the volume. If all
other space is used up, then the MFT zone will be
shrunk dynamically, so this has no impact on the
amount of free space. However, it can have an impact
on performance by affecting fragmentation of the MFT.
In general use the default. If you have a lot of small
files then use a higher value. The values have the
following meaning:
Value MFT zone size (% of volume size)
1 12.5%
2 25%
3 37.5%
4 50%
Note this option is irrelevant for read-only mounts.
Features
========
- Implementation of NTFS read support functionally equivalent to the old ntfs
driver.
Known bugs and (mis-)features
=============================
- None
Please send bug reports/comments/feedback/abuse to the Linux-NTFS development
list at sourceforge: linux-ntfs-dev@lists.sourceforge.net
ChangeLog
=========
Note that a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
TNG-0.0.8:
- Started ChangeLog.
...@@ -576,6 +576,37 @@ CONFIG_HPFS_FS ...@@ -576,6 +576,37 @@ CONFIG_HPFS_FS
say M here and read <file:Documentation/modules.txt>. If unsure, say M here and read <file:Documentation/modules.txt>. If unsure,
say N. say N.
CONFIG_NTFS_FS
NTFS is the file system of Microsoft Windows NT/2000/XP. For more
information see <file:Documentation/filesystems/ntfs.txt>. Saying Y
here would allow you to read from NTFS partitions.
This file system is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called ntfs.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>. If you
are not using Windows NT/2000/XP in addition to Linux on your computer
it is safe to say N.
CONFIG_NTFS_DEBUG
If you are experiencing any problems with the NTFS file system, say
Y here. This will result in additional consistency checks to be
performed by the driver as well as additional debugging messages to
be written to the system log. Note that debugging messages are
disabled by default. To enable them, supply the option debug_msgs=1
at the kernel command line when booting the kernel or as an option
to insmod when loading the ntfs module. Once the driver is active,
you can enable debugging messages by doing (as root):
echo 1 > /proc/sys/fs/ntfs-debug
Replacing the "1" with "0" would disable debug messages.
If you leave debugging messages disable, this results in little
overhead, but enabling debug messages results in very significant
slowdown of the system.
When reporting bugs, please try to have available a full dump of
debugging messages while the misbehaviour was occurring.
CONFIG_SYSV_FS CONFIG_SYSV_FS
SCO, Xenix and Coherent are commercial Unix systems for Intel SCO, Xenix and Coherent are commercial Unix systems for Intel
machines, and Version 7 was used on the DEC PDP-11. Saying Y machines, and Version 7 was used on the DEC PDP-11. Saying Y
......
...@@ -62,6 +62,9 @@ tristate 'Minix fs support' CONFIG_MINIX_FS ...@@ -62,6 +62,9 @@ tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS
tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS
dep_mbool ' NTFS debugging support' CONFIG_NTFS_DEBUG $CONFIG_NTFS_FS
tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
bool '/proc file system support' CONFIG_PROC_FS bool '/proc file system support' CONFIG_PROC_FS
......
...@@ -52,6 +52,7 @@ subdir-$(CONFIG_SYSV_FS) += sysv ...@@ -52,6 +52,7 @@ subdir-$(CONFIG_SYSV_FS) += sysv
subdir-$(CONFIG_SMB_FS) += smbfs subdir-$(CONFIG_SMB_FS) += smbfs
subdir-$(CONFIG_NCP_FS) += ncpfs subdir-$(CONFIG_NCP_FS) += ncpfs
subdir-$(CONFIG_HPFS_FS) += hpfs subdir-$(CONFIG_HPFS_FS) += hpfs
subdir-$(CONFIG_NTFS_FS) += ntfs
subdir-$(CONFIG_UFS_FS) += ufs subdir-$(CONFIG_UFS_FS) += ufs
subdir-$(CONFIG_EFS_FS) += efs subdir-$(CONFIG_EFS_FS) += efs
subdir-$(CONFIG_JFFS_FS) += jffs subdir-$(CONFIG_JFFS_FS) += jffs
......
...@@ -33,7 +33,7 @@ ToDo: ...@@ -33,7 +33,7 @@ ToDo:
in between. Either need different type of optimization as above or in between. Either need different type of optimization as above or
need to change the read/write spinlock to a read/write semaphore. need to change the read/write spinlock to a read/write semaphore.
tng-0.0.8 - Work in progress. tng-0.0.8 - 08/03/2002 - BitKeeper ChangeSet 1.457
- Replace bdevname(sb->s_dev) with sb->s_id. - Replace bdevname(sb->s_dev) with sb->s_id.
- Remove now superfluous new-line characters in all callers of - Remove now superfluous new-line characters in all callers of
...@@ -108,6 +108,16 @@ tng-0.0.8 - Work in progress. ...@@ -108,6 +108,16 @@ tng-0.0.8 - Work in progress.
- Check for lowest_vcn != 0 in ntfs_read_inode() and mark the inode as - Check for lowest_vcn != 0 in ntfs_read_inode() and mark the inode as
bad if found. bad if found.
- Update to 2.5.6-pre2 changes in struct address_space. - Update to 2.5.6-pre2 changes in struct address_space.
- Import Sourceforge CVS repository into BitKeeper repository:
http://linux-ntfs.bkbits.net/ntfs-tng-2.5
- Update fs/Makefile, fs/Config.help, fs/Config.in, and
Documentation/filesystems/ntfs.txt for NTFS TNG.
- Create kernel configuration option controlling whether debugging
is enabled or not.
- Add the required export of end_buffer_io_sync() from the patches
directory to the kernel code.
- Update inode.c::ntfs_show_options() with show_inodes mount option.
- Update errors mount option.
tng-0.0.7 - 13/02/2002 - The driver is now feature complete for read-only! tng-0.0.7 - 13/02/2002 - The driver is now feature complete for read-only!
......
...@@ -9,8 +9,9 @@ obj-m := $(O_TARGET) ...@@ -9,8 +9,9 @@ obj-m := $(O_TARGET)
EXTRA_CFLAGS = -DNTFS_VERSION=\"TNG-0.0.8\" EXTRA_CFLAGS = -DNTFS_VERSION=\"TNG-0.0.8\"
# Uncomment this to enable debugging code. ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
This diff is collapsed.
...@@ -1349,6 +1349,13 @@ void ntfs_clear_big_inode(struct inode *vi) ...@@ -1349,6 +1349,13 @@ void ntfs_clear_big_inode(struct inode *vi)
return; return;
} }
static const option_t si_readdir_opts_arr[] = {
{ SHOW_SYSTEM, "system" },
{ SHOW_WIN32, "win32" },
{ SHOW_DOS, "dos" },
{ 0, NULL }
};
/** /**
* ntfs_show_options - show mount options in /proc/mounts * ntfs_show_options - show mount options in /proc/mounts
* @sf: seq_file in which to write our mount options * @sf: seq_file in which to write our mount options
...@@ -1363,6 +1370,7 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) ...@@ -1363,6 +1370,7 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt)
{ {
ntfs_volume *vol = NTFS_SB(mnt->mnt_sb); ntfs_volume *vol = NTFS_SB(mnt->mnt_sb);
int i; int i;
char *s;
seq_printf(sf, ",uid=%i", vol->uid); seq_printf(sf, ",uid=%i", vol->uid);
seq_printf(sf, ",gid=%i", vol->gid); seq_printf(sf, ",gid=%i", vol->gid);
...@@ -1372,14 +1380,26 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) ...@@ -1372,14 +1380,26 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt)
seq_printf(sf, ",fmask=0%o", vol->fmask); seq_printf(sf, ",fmask=0%o", vol->fmask);
seq_printf(sf, ",dmask=0%o", vol->dmask); seq_printf(sf, ",dmask=0%o", vol->dmask);
} }
seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier);
seq_printf(sf, ",nls=%s", vol->nls_map->charset); seq_printf(sf, ",nls=%s", vol->nls_map->charset);
for (i = 0; on_errors_arr[i].val; i++) { switch (vol->readdir_opts) {
if (on_errors_arr[i].val == vol->on_errors) { case SHOW_ALL:
seq_printf(sf, ",errors=%s", on_errors_arr[i].str); seq_printf(sf, ",show_inodes=all");
break;
case SHOW_POSIX:
seq_printf(sf, ",show_inodes=posix");
break; break;
default:
for (i = 0; si_readdir_opts_arr[i].val; i++) {
if (si_readdir_opts_arr[i].val & vol->readdir_opts)
seq_printf(sf, ",show_inodes=%s",
si_readdir_opts_arr[i].str);
} }
} }
for (i = 0; on_errors_arr[i].val; i++) {
if (on_errors_arr[i].val & vol->on_errors)
seq_printf(sf, ",errors=%s", on_errors_arr[i].str);
}
seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier);
return 0; return 0;
} }
...@@ -36,9 +36,11 @@ static unsigned long ntfs_nr_compression_users = 0; ...@@ -36,9 +36,11 @@ static unsigned long ntfs_nr_compression_users = 0;
/* Error constants/strings used in inode.c::ntfs_show_options(). */ /* Error constants/strings used in inode.c::ntfs_show_options(). */
typedef enum { typedef enum {
/* One of these must be present, default is ON_ERRORS_CONTINUE. */
ON_ERRORS_PANIC = 0x01, ON_ERRORS_PANIC = 0x01,
ON_ERRORS_REMOUNT_RO = 0x02, ON_ERRORS_REMOUNT_RO = 0x02,
ON_ERRORS_CONTINUE = 0x04, ON_ERRORS_CONTINUE = 0x04,
/* Optional, can be combined with any of the above. */
ON_ERRORS_RECOVER = 0x10, ON_ERRORS_RECOVER = 0x10,
} ON_ERRORS_ACTIONS; } ON_ERRORS_ACTIONS;
...@@ -47,9 +49,6 @@ const option_t on_errors_arr[] = { ...@@ -47,9 +49,6 @@ const option_t on_errors_arr[] = {
{ ON_ERRORS_REMOUNT_RO, "remount-ro", }, { ON_ERRORS_REMOUNT_RO, "remount-ro", },
{ ON_ERRORS_CONTINUE, "continue", }, { ON_ERRORS_CONTINUE, "continue", },
{ ON_ERRORS_RECOVER, "recover" }, { ON_ERRORS_RECOVER, "recover" },
{ ON_ERRORS_RECOVER | ON_ERRORS_PANIC, "recover_or_panic" },
{ ON_ERRORS_RECOVER | ON_ERRORS_REMOUNT_RO, "recover_or_remount-ro" },
{ ON_ERRORS_RECOVER | ON_ERRORS_CONTINUE, "recover_or_continue" },
{ 0, NULL } { 0, NULL }
}; };
...@@ -288,8 +287,8 @@ static BOOL parse_options(ntfs_volume *vol, char *opt) ...@@ -288,8 +287,8 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
vol->mft_zone_multiplier = 1; vol->mft_zone_multiplier = 1;
if (on_errors != -1) if (on_errors != -1)
vol->on_errors = on_errors; vol->on_errors = on_errors;
if (!vol->on_errors) if (!vol->on_errors || vol->on_errors == ON_ERRORS_RECOVER)
vol->on_errors = ON_ERRORS_CONTINUE; vol->on_errors |= ON_ERRORS_CONTINUE;
if (uid != (uid_t)-1) if (uid != (uid_t)-1)
vol->uid = uid; vol->uid = uid;
if (gid != (gid_t)-1) if (gid != (gid_t)-1)
...@@ -1837,7 +1836,7 @@ static int __init init_ntfs_fs(void) ...@@ -1837,7 +1836,7 @@ static int __init init_ntfs_fs(void)
#ifdef MODULE #ifdef MODULE
" MODULE" " MODULE"
#endif #endif
"]. Copyright (c) 2001 Anton Altaparmakov.\n"); "]. Copyright (c) 2001,2002 Anton Altaparmakov.\n");
ntfs_debug("Debug messages are enabled."); ntfs_debug("Debug messages are enabled.");
......
This diff is collapsed.
#ifndef _LINUX_NTFS_FS_I_H
#define _LINUX_NTFS_FS_I_H
/*
* Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
* and VCN, to allow for type checking and better code readability.
*/
typedef __s64 VCN;
typedef __s64 LCN;
/**
* run_list - in memory vcn to lcn mapping array
* @vcn: starting vcn of the current array element
* @lcn: starting lcn of the current array element
* @length: length in clusters of the current array element
*
* The last vcn (in fact the last vcn + 1) is reached when length == 0.
*
* When lcn == -1 this means that the count vcns starting at vcn are not
* physically allocated (i.e. this is a hole / data is sparse).
*/
typedef struct { /* In memory vcn to lcn mapping structure element. */
VCN vcn; /* vcn = Starting virtual cluster number. */
LCN lcn; /* lcn = Starting logical cluster number. */
__s64 length; /* Run length in clusters. */
} run_list;
/*
* The NTFS in-memory inode structure. It is just used as an extension to the
* fields already provided in the VFS inode.
*/
struct ntfs_inode_info {
struct inode *inode; /* Pointer to the inode structure of this
ntfs_inode_info structure. */
unsigned long state; /* NTFS specific flags describing this inode.
See fs/ntfs/ntfs.h:ntfs_inode_state_bits. */
run_list *run_list; /* If state has the NI_NonResident bit set,
the run list of the unnamed data attribute
(if a file) or of the index allocation
attribute (directory). If run_list is NULL,
the run list has not been read in or has
been unmapped. If NI_NonResident is clear,
the unnamed data attribute is resident (file)
or there is no $I30 index allocation
attribute (directory). In that case run_list
is always NULL.*/
__s32 nr_extents; /* The number of extents[], if this is a base
mft record, -1 if this is an extent record,
and 0 if there are no extents. */
struct rw_semaphore mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
(un)map_mft_record_for_*() functions. Do NOT
touch from anywhere else or the ntfs divil
will appear and take your heart out with a
blunt spoon! You have been warned. (-8 */
union {
struct { /* It is a directory. */
__u32 index_block_size; /* Size of an index block. */
__u8 index_block_size_bits; /* Log2 of the size of an
an index block. */
__s64 bmp_size; /* Size of the $I30 bitmap. */
run_list *bmp_rl; /* Run list for the $I30 bitmap
if it is non-resident. */
};
struct { /* It is a compressed file. */
__u32 compression_block_size; /* Size of a compression
block (cb). */
__u8 compression_block_size_bits; /* Log2 of the size
of a cb. */
__u8 compression_block_clusters; /* Number of clusters
per compression
block. */
};
};
union { /* This union is only used if nr_extents != 0. */
struct { /* nr_extents > 0 */
__s64 i_ino; /* The inode number of the
extent mft record. */
__u32 i_generation; /* The i_generation of the
extent mft record. */
} *extents; /* The currently known of extents, sorted in
ascending order. */
struct { /* nr_exents == -1 */
__s64 i_ino; /* The inode number of the base
mft record of this extent. */
__u32 i_generation; /* The i_generation of the base
mft record. */
} base; /* The base mft record of this extent. */
};
};
#endif /* _LINUX_NTFS_FS_I_H */
#ifndef _LINUX_NTFS_FS_SB_H
#define _LINUX_NTFS_FS_SB_H
/* 2-byte Unicode character type. */
typedef __u16 uchar_t;
/*
* The NTFS in memory super block structure.
*/
struct ntfs_sb_info {
/*
* FIXME: Reorder to have commonly used together element within the
* same cache line, aiming at a cache line size of 32 bytes. Aim for
* 64 bytes for less commonly used together elements. Put most commonly
* used elements to front of structure. Obviously do this only when the
* structure has stabilized... (AIA)
*/
/* Device specifics. */
struct super_block *sb; /* Pointer back to the super_block,
so we don't have to get the offset
every time. */
LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes
sized blocks on the device. */
/* Configuration provided by user at mount time. */
uid_t uid; /* uid that files will be mounted as. */
gid_t gid; /* gid that files will be mounted as. */
mode_t fmask; /* The mask for file permissions. */
mode_t dmask; /* The mask for directory
permissions. */
__u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
__u8 on_errors; /* What to do on file system errors. */
/* NTFS bootsector provided information. */
__u16 sector_size; /* in bytes */
__u8 sector_size_bits; /* log2(sector_size) */
__u32 cluster_size; /* in bytes */
__u32 cluster_size_mask; /* cluster_size - 1 */
__u8 cluster_size_bits; /* log2(cluster_size) */
__u32 mft_record_size; /* in bytes */
__u32 mft_record_size_mask; /* mft_record_size - 1 */
__u8 mft_record_size_bits; /* log2(mft_record_size) */
__u32 index_record_size; /* in bytes */
__u32 index_record_size_mask; /* index_record_size - 1 */
__u8 index_record_size_bits; /* log2(index_record_size) */
union {
LCN nr_clusters; /* Volume size in clusters. */
LCN nr_lcn_bits; /* Number of bits in lcn bitmap. */
};
LCN mft_lcn; /* Cluster location of mft data. */
LCN mftmirr_lcn; /* Cluster location of copy of mft. */
__u64 serial_no; /* The volume serial number. */
/* Mount specific NTFS information. */
__u32 upcase_len; /* Number of entries in upcase[]. */
uchar_t *upcase; /* The upcase table. */
LCN mft_zone_start; /* First cluster of the mft zone. */
LCN mft_zone_end; /* First cluster beyond the mft zone. */
struct inode *mft_ino; /* The VFS inode of $MFT. */
struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
mft record bitmap ($MFT/$BITMAP). */
union {
__s64 nr_mft_records; /* Number of records in the mft. */
__s64 nr_mft_bits; /* Number of bits in mft bitmap. */
};
struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */
run_list *mftbmp_rl; /* Run list for $MFT/$BITMAP. */
struct inode *mftmirr_ino; /* The VFS inode of $MFTMirr. */
struct inode *lcnbmp_ino; /* The VFS inode of $Bitmap. */
struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
cluster bitmap ($Bitmap/$DATA). */
struct inode *vol_ino; /* The VFS inode of $Volume. */
unsigned long vol_flags; /* Volume flags (VOLUME_*). */
__u8 major_ver; /* Ntfs major version of volume. */
__u8 minor_ver; /* Ntfs minor version of volume. */
struct inode *root_ino; /* The VFS inode of the root
directory. */
struct inode *secure_ino; /* The VFS inode of $Secure (NTFS3.0+
only, otherwise NULL). */
struct nls_table *nls_map;
};
#endif /* _LINUX_NTFS_FS_SB_H */
This diff is collapsed.
...@@ -164,7 +164,8 @@ EXPORT_SYMBOL(d_alloc); ...@@ -164,7 +164,8 @@ EXPORT_SYMBOL(d_alloc);
EXPORT_SYMBOL(d_lookup); EXPORT_SYMBOL(d_lookup);
EXPORT_SYMBOL(__d_path); EXPORT_SYMBOL(__d_path);
EXPORT_SYMBOL(mark_buffer_dirty); EXPORT_SYMBOL(mark_buffer_dirty);
EXPORT_SYMBOL(set_buffer_async_io); /* for reiserfs_writepage */ EXPORT_SYMBOL(end_buffer_io_sync);
EXPORT_SYMBOL(set_buffer_async_io);
EXPORT_SYMBOL(__mark_buffer_dirty); EXPORT_SYMBOL(__mark_buffer_dirty);
EXPORT_SYMBOL(__mark_inode_dirty); EXPORT_SYMBOL(__mark_inode_dirty);
EXPORT_SYMBOL(get_empty_filp); EXPORT_SYMBOL(get_empty_filp);
......
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