Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/include
In directory usw-pr-cvs1:/tmp/cvs-serv3974/include
Modified Files:
attrib.h mft.h volume.h
Log Message:
User space conversion of locking complete. I settled for using simple spinlocks
and atomic variables and instead of deadlocking/livelocking when using
spin_lock(), use spin_trylock() in a while letting go of the cpu between each
call and making a maximum of 100 iterations (or we return EDEADLK error code).
This is not the most efficient way, especially as can't have multiple readers
but it is the simplest way to go about things.
Should now have (almost) all required helper functions for dealing with mft
entries implemented.
Now need the file handling and then convert the whole project to use the new
code and then can finally get back to work on attribute searching...
Index: attrib.h
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/include/attrib.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -U2 -r1.22 -r1.23
--- attrib.h 2001/04/05 20:14:45 1.22
+++ attrib.h 2001/04/08 01:58:29 1.23
@@ -1710,8 +1710,7 @@
*
* 0: Check errno:
- * If zero, the lcn corresponding to the vcn is zero.
- * Otherwise, there was an error and errno contains the error code,
- * the most interesting error being ENOENT indicating we are
- * looking for a vcn which doesn't exist.
+ * 0 The lcn corresponding to the vcn is really zero.
+ * ENOENT We are looking for a vcn which doesn't exist.
+ * EINVAL Either @rl or @vcn are invalid.
*
* -1: The lcn is sparse, i.e. it's contents are zero and there is no disk
Index: mft.h
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/include/mft.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -U2 -r1.15 -r1.16
--- mft.h 2001/04/05 20:14:45 1.15
+++ mft.h 2001/04/08 01:58:29 1.16
@@ -30,5 +30,5 @@
#include <asm/atomic.h>
-#include <asm/semaphore.h>
+#include <linux/spinlock.h>
#include <linux/list.h>
@@ -36,4 +36,5 @@
#include "ntfs_rec.h"
#include "volume.h"
+#include "support.h"
#define is_mft_record(x) ( is_file_record(x) )
@@ -149,4 +150,6 @@
} __attribute__ ((__packed__));
__u64 full_ref; /* Mft reference as one value.*/
+ __u64; /* Unnamed reference as one
+ value. */
} __attribute__ ((__packed__)) MFT_REFERENCE;
@@ -268,5 +271,5 @@
* max_files: Maximum number of nr_open_files + nr_closed_files.
*
- * files_sem: Read write semaphore to serialize access to the above
+ * files_lock: Spinlock to serialize access to the above
* structure members (open_files, nr_open_files,
* closed_files, nr_closed_files and max_files).
@@ -289,4 +292,7 @@
* nr_mft_entries: Number of mft_entries.
*
+ * mft_entries_lock: Spinlock to serialize access to
+ * {nr_}mft_entries.
+ *
* dirty_mft_entries: Linked list of all loaded mft records which are dirty.
* Used by the disk writer thread. When a mft_entry is
@@ -297,7 +303,6 @@
* nr_dirty_mft_entries: Number of dirty mft_entries.
*
- * mft_entries_sem: Read write semaphore to serialize access to the above
- * structure members (mft_entries, nr_mft_entries and their
- * dirty equivalents).
+ * dirty_mft_entries_lock: Spinlock to serialize access to
+ * {nr_}dirty_mft_entries.
*
* The mft_entry struct.
@@ -310,5 +315,5 @@
* set.)
*
- * m_rec_sem: Read write semaphore controlling access to m_rec. Only one
+ * m_rec_lock: Spinlock controlling access to m_rec. Only one
* writer at a time (and no readers while one writer) as the mft
* record will be corrupt during the write process.
@@ -316,9 +321,13 @@
* m_flags: Atomic flags describing the mft entry / record:
*
- * mapped: Is the MFT_RECORD actually in memory? (Is mrec valid?)
+ * mapped: Is the MFT_RECORD actually in memory? (Is mrec valid?)
*
- * dirty: Does the record need to be written to disk? (If not, it
- * is safe to discard m_rec, but only if m_count is zero
- * and we are holding m_rec_sem for writing.)
+ * dirty: Does the record need to be written to disk? (If not, it is safe
+ * to discard m_rec, but only if m_count is zero and we are
+ * holding m_rec_lock for writing.)
+ *
+ * error: When reading the entry from disk it was detected that it is
+ * corrupt. For example, it could be that a multi sector transfer
+ * error was detected.
*
* m_ref: Mft reference of the mft record described by this entry. (This
@@ -329,9 +338,9 @@
* first if dirty flag is set).
*
- * m_sem: Read write semaphore controlling access to this entry.
+ * m_lock: Lock controlling access to this entry.
*
- * m_list: Hook for the mft_entries linked list.
+ * m_list: Anchor for the mft_entries linked list.
*
- * m_dirty_list: Hook for the dirty_mft_enties linked list. (Only valid if
+ * m_dirty_list: Anchor for the dirty_mft_enties linked list. (Only valid if
* the dirty flag is set.)
*
@@ -371,5 +380,5 @@
* a possible f_nr_mft_entries, but refs is shorter to write. (-;
*
- * f_sem: Read write semaphore for serializing access to the above struct
+ * f_lock: Spinlock for serializing access to the above struct
* members (f_mft_refs, f_mft_entries and f_nr_mft_refs).
*
@@ -379,5 +388,5 @@
* below the idea of files.
*
- * f_list: Hook into vol->open/closed_files list.
+ * f_list: Anchor into vol->open/closed_files list.
*
* Notes:
@@ -392,5 +401,6 @@
#define ME_mapped 0
#define ME_dirty 1
- /* bits 2-31 reserved for future use */
+#define ME_error 2
+ /* bits 3-31 reserved for future use */
#define MftEntryMapped(me) test_bit(ME_mapped, &(me)->m_flags)
@@ -402,11 +412,15 @@
#define ClearMftEntryDirty(me) clear_bit(ME_dirty, &(me)->m_flags)
+#define MftEntryError(me) test_bit(ME_error, &(me)->m_flags)
+#define SetMftEntryError(me) set_bit(ME_error, &(me)->m_flags)
+#define ClearMftEntryError(me) clear_bit(ME_error, &(me)->m_flags)
+
typedef struct {
MFT_RECORD *m_rec;
- struct rw_semaphore m_rec_sem;
+ struct spinlock_t m_rec_lock;
unsigned int m_flags;
MFT_REFERENCE m_ref;
atomic_t m_count;
- struct rw_semaphore m_sem;
+ struct spinlock_t m_lock;
struct list_head m_list;
struct list_head m_dirty_list;
@@ -414,17 +428,9 @@
} mft_entry;
-void __set_mft_entry_dirty(mft_entry *me);
-
-static __inline__ void set_mft_entry_dirty(mft_entry *me)
-{
- if (!test_and_set_bit(ME_dirty, &me->m_flags))
- __set_mft_entry_dirty(me);
-}
-
typedef struct {
MFT_REFERENCE *f_mft_refs;
mft_entry *f_mft_entries;
int f_nr_mft_refs;
- struct rw_semaphore f_sem;
+ struct spinlock_t f_lock;
atomic_t f_count;
struct list_head f_list;
@@ -432,49 +438,83 @@
/**
- * __allocate_mft_entry - allocate a new mft_entry and initialize it
+ * flush_mft_entry - flush a mft_entry to disk
+ * @me: mft_entry to flush
+ *
+ * The mft entry is written to disk (if dirty) and marked clean. It is also
+ * removed from the dirty list of the volume (if it is on the list).
*
- * Return the new mft_entry on success or NULL with errno set to the error code.
+ * This function must be called with the volume's dirty_mft_entries_lock held,
+ * if the entry is on the volume's mft_entries_dirty list. If it is not, the
+ * lock doesn't need to be held.
+ *
+ * Return 0 on success and -ERRNO on error. Following failure return values
+ * are defined:
+ * -EBADF Mft_entry is corrupt (error flag set).
+ * -EDEADLK Couldn't acquire a necessary lock.
+ * -EIO Writing to disk failed.
+ * -ENOTSUP Tried to write to a sparse mft record. Should never
+ * happen but if it does there is a bug. See implementation
+ * of flush_mft_entry() in mft.c for details.
+ * -EPERM Tried to write to cluster 0, which would overwrite the
+ * bootsector. There must be a bug somewhere...
+ * others Error codes returned by vcn_to_lcn() function; meaning
+ * we couldn't locate the position on disk for the entry.
*/
-extern __inline__ mft_entry *__allocate_mft_entry(void);
+int flush_mft_entry(mft_entry *me);
/**
- * free_mft_entry - free a mft_entry
- * @me: mft_entry to free
+ * __set_mft_entry_dirty - internal use only, use set_mft_entry_dirty instead
+ * @me: mft entry to set dirty
+ *
+ * Return true on success or false if one of the locks couldn't be acquired.
*
- * Must be unlocked, use count 0, etc, or we return -EBUSY.
- * Return 0 on success and -ERRNO on error.
+ * See set_mft_entry_dirty().
*/
-extern __inline__ int free_mft_entry(mft_entry *me);
+BOOL __set_mft_entry_dirty(mft_entry *me);
/**
- * insert_mft_entry - insert a mft_entry in a volume
- * @vol: volume to insert into
- * @me: mft_entry to insert
- * @mref: mft reference the mft entry will have
- * @mrec: optional loaded MFT_RECORD corresponding to @mref
- * @dirty: boolean whether @mrec is dirty or not (only if @mrec present)
- *
- * Initialize the mft_entry with the values of @mref, @mrec and @dirty and
- * insert it into the volume @vol. If @mrec is not present, the mft record
- * corresponding to @mref is loaded from the volume.
+ * set_mft_entry_dirty - set an mft entry dirty
+ * @me: mft entry to set dirty
*
- * Return 0 on success and -ERRNO on error.
+ * If the mft entry @me is not dirty it is added to the dirty_mft_entries list
+ * of the volume to which @me belongs and the dirty flag of the entry is set.
+ *
+ * Return true on success or false on error.
+ *
+ * If setting the mft entry dirty fails, we try to flush it to disk and make
+ * it clean to avoid problems. If this succeeds, return true, and not false.
+ *
+ * If false is returned, this means that we couldn't set the mft entry dirty
+ * and we also couldn't flush it to disk to make it clean again. This means
+ * that the caller has to make sure that the contents are not lost, which they
+ * would be normally, unless a subsequent call to set_mft_entry_dirty() or
+ * flush_mft_entry() succeeds.
*/
-int insert_mft_entry(ntfs_volume *vol, mft_entry *me, MFT_REFERENCE mref,
- MFT_RECORD *mrec, int dirty);
+static __inline__ BOOL set_mft_entry_dirty(mft_entry *me)
+{
+ if (test_and_set_bit(ME_dirty, &me->m_flags) ||
+ __set_mft_entry_dirty(me))
+ return TRUE;
+ return flush_mft_entry(me) == 0;
+}
/**
- * remove_mft_entry - remove a mft_entry from it's volume and free it
- * @me: mft_entry to remove and free
- *
- * The mft entry must have a use count of 0, or we return -EBUSY.
+ * __allocate_mft_entry - allocate a new mft_entry and initialize it
+ *
+ * Return the new mft_entry on success or NULL with errno set to the error
+ * code returned from malloc().
+ */
+extern __inline__ mft_entry *__allocate_mft_entry(void);
+
+/**
+ * __free_mft_entry - free a mft_entry
+ * @me: mft_entry to free
*
- * Remove the mft entry from the volume, flush it to disk if necessary,
- * and finally free all memory that was used by the entry including the entry
- * itself.
+ * Return 0 on success and -EBUSY on error.
*
- * Return 0 on success and -ERRNO on error.
+ * To succeed, the entry must be unlocked, clean, have a use count of 0, and
+ * it must not be mapped. If any of these are false, return -EBUSY.
*/
-int remove_mft_entry(mft_entry *me);
+extern __inline__ int __free_mft_entry(mft_entry *me);
/**
@@ -482,7 +522,21 @@
* @me: mft entry to map
*
- * Map an (unmapped) mft entry into memory not increasing the use count.
+ * Map mft entry @me into memory (if unmapped) not increasing the use count.
*
- * Return 0 on success or -ERRNO on error.
+ * Return 0 on success or -ERRNO on error. If an I/O error of any kind occurs,
+ * including multi sector transfer (mst) errors being detected, the error flag
+ * is set on the entry.
+ *
+ * Following failure return values are defined:
+ * -EDEADLK Couldn't acquire a necessary lock.
+ * -EIO Reading from disk failed (or mst error detected). Error
+ * flag has been set.
+ * -ENOTSUP Tried to read a sparse mft record. Currently not
+ * implemented as I am not sure whether this can ever
+ * occur.
+ * -EPERM Tried to read cluster 0, which would return the
+ * bootsector data. There must be a bug somewhere...
+ * others Error codes returned by vcn_to_lcn() function; meaning
+ * we couldn't locate the position on disk for the entry.
*/
int __map_mft_entry(mft_entry *me);
@@ -492,7 +546,9 @@
* @me: mft entry to map
*
- * Map an (unmapped) mft entry into memory and increase the use count.
+ * Increase the use count of the entry @me and map it into memory (if it is not
+ * mapped).
*
- * Return 0 on success or -ERRNO on error.
+ * Return 0 on success or -ERRNO on error. See __map_mft_entry() for more
+ * details on the returned error codes.
*/
static __inline__ int map_mft_entry(mft_entry *me)
@@ -523,47 +579,79 @@
* @me: mft entry to unmap
*
- * Actually unmap the mft entry (only if use count is 0).
+ * Unmap the mft entry (only if use count is 0) and free all used memory.
*
- * Return zero on success or -ERRNO on error.
+ * Return zero on success or -ERRNO on error. On error, the following values
+ * are returned:
+ * -EBUSY Use count is above zero or couldn't sync dirty entry.
+ * -EDEADLK Failed to acquire a necessary lock.
+ * others Values returned by flush_mft_entry().
*/
int __unmap_mft_entry(mft_entry *me);
/**
- * flush_mft_entry - flush a mft_entry to disk
- * @me: mft_entry to flush
+ * insert_mft_entry - insert a mft_entry into a volume
+ * @vol: volume to insert into
+ * @me: mft_entry to insert
+ * @mref: mft reference the mft entry will have
+ * @mrec: loaded MFT_RECORD corresponding to @mref (optional)
+ * @dirty: true if @mrec is dirty, false otherwise (only if @mrec present)
*
- * The mft entry is written to disk (if dirty) and marked clean. It is also
- * removed from the dirty list of the volume.
+ * Initialize the mft_entry with the values of @mref, @mrec and @dirty and
+ * insert it into the volume @vol. If @mrec is not present, the mft record
+ * corresponding to @mref is loaded from the volume.
+ *
+ * Return 0 on success and -ERRNO on error. On error, the following values are
+ * returned:
+ * -EDEADLK Failed to acquire a necessary lock.
+ * -EEXIST Entry alread exists in the volume. There must be a bug
+ * somewhere. This should _really_ never happen.
+ * others Values returned by flush_mft_entry.
+ */
+int insert_mft_entry(ntfs_volume *vol, mft_entry *me, const MFT_REFERENCE mref,
+ const MFT_RECORD *mrec, const BOOL dirty);
+
+/**
+ * remove_mft_entry - remove a mft_entry from its volume and free it
+ * @me: mft_entry to remove and free
+ *
+ * Remove the mft entry @me from its volume, flush it to disk if necessary,
+ * and finally free all memory that was used by the entry including the entry
+ * itself. Note, the mft entry must have a use count of zero.
*
- * Return 0 on success and -ERRNO on error.
+ * Return 0 on success and -ERRNO on error. The defined error codes are:
+ * -EBUSY The use count of the entry is above 0.
+ * -EDEADLK Failed to acquire a necessary lock.
+ * others Values returned by flush_mft_entry.
*/
-int flush_mft_entry(mft_entry *me);
+int remove_mft_entry(mft_entry *me);
/**
- * ntfs_open_by_mref - open an ntfs file, i.e. mft record, given a mft reference
+ * ntfs_open_by_mref - open an ntfs file (mft record), given its mft reference
* @vol: ntfs volume to operate on
* @mref: mft_reference of base mft record to open
*
* Open an ntfs_file (using file to mean any base mft record) given the mft
- * reference of the mft record (i.e. the inode number). To do this allocate an
+ * reference of the mft record (i.e. the inode number). To do this, allocate an
* ntfs_file structure (adding it to the vol->open_files array), or if the file
* is already loaded, just find it in the vol->open_/closed_files arrays.
*
- * Return a pointer to the ntfs_file structure in the vol->open_files array.
+ * Return a pointer to the ntfs_file structure in the vol->open_files array or
+ * NULL on error with errno containing the error code.
+ *
* This pointer should be treated completely opaquely by the user! Never
* use it for anything except as a parameter to functions taking a ntfs_file
* pointer as a parameter.
*/
-ntfs_file *ntfs_open_by_mref(const ntfs_volume *vol, const MFT_REFERENCE *mref);
+ntfs_file *ntfs_open_by_mref(ntfs_volume *vol, const MFT_REFERENCE *mref);
/**
* ntfs_close - close an ntfs_file
* @vol: ntfs volume to operate on
- * @fref: ntfs_file pointer to close
+ * @f: ntfs_file pointer to close
*
- * Close a previously opened ntfs file. Return zero on success or -1 on
- * error, where errno is the error number.
+ * Close a previously opened ntfs file. Return zero on success or -ERRNO on
+ * error.
*/
-int ntfs_close(ntfs_file *fref);
+int ntfs_close(ntfs_file *f);
#endif /* defined MFT_H */
Index: volume.h
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/include/volume.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -U2 -r1.7 -r1.8
--- volume.h 2001/04/07 17:30:10 1.7
+++ volume.h 2001/04/08 01:58:29 1.8
@@ -25,8 +25,9 @@
#include <stdio.h>
#include <asm/atomic.h>
-#include <asm/semaphore.h>
+#include <linux/spinlock.h>
#include <linux/list.h>
#include "attrib.h"
+#include "support.h"
/*
@@ -109,5 +110,5 @@
files which are not open any more. */ int nr_closed_files; /* Number of closed files. */
int max_files; /* Maximum number of nr_open_files + nr_ closed_files. */
- rw_semaphore files_sem; /* Read write semaphore to serialize
+ spinlock_t files_lock; /* Spinlock to serialize
access to open_files, nr_open_files,
closed_files, nr_closed_files and
@@ -120,21 +121,35 @@
struct pointers. */
int nr_mft_entries; /* Number of mft_entries. */
+ spinlock_t mft_entries_lock; /* Spinlock to serialize
+ access to {nr_}mft_entries. */
struct list_head dirty_mft_entries; /* Linked list of all loaded mft
- records which are dirty. */
- int nr_dirty_mft_entries; /* Number of dirty mft_entries. */
- rw_semaphore mft_entries_sem; /* Read write semaphore to serialize
- access to mft_entries,
- nr_mft_entries and their dirty
- equivalents. */
- struct list_head v_list; /* Anchor for list of all mounted
- volumes. */
+ records which are dirty. */
+ int nr_dirty_mft_entries; /* Number of dirty mft_entries. */
+ spinlock_t dirty_mft_entries_lock; /* Spinlock to serialize access to
+ {nr_}dirty_mft_entries. */
+ struct list_head v_list; /* Anchor for list of all mounted
+ volumes. */
} ntfs_volume;
/**
+ * ntfs_sync_volume - sync a mounted ntfs volume to physical storage
+ * @vol: ntfs volume to sync
+ *
+ * This function syncs a mounted ntfs volumes to physical storage.
+ *
+ * Returns true on success or false on error. In the later case errno describes
+ * the error.
+ *
+ * The important error codes are:
+ * TODO: List them... (AIA)
+ */
+BOOL ntfs_sync_volume(ntfs_volume *vol);
+
+/**
* ntfs_mount - open ntfs volume
* @name: name of device/file to open
*
- * This function opens an ntfs volume. @name should contain the name of the
- * device/file to open as the ntfs volume.
+ * This function mounts an ntfs volume. @name should contain the name of the
+ * device/file to mount as the ntfs volume.
*
* The function opens the device or file @name and verifies that it contains a
@@ -163,6 +178,6 @@
* itself) associated with the ntfs volume @vol.
*
- * Return 1 on success. On error return zero with errno set appropriately (most
- * likely to one of -EAGAIN, -EBUSY or -EINVAL). The -EAGAIN error means that
+ * Return true on success. On error return false with errno set appropriately
+ * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
* an operation is in progress and if you try the close later the operation
* might be completed and the close succeed.
@@ -181,5 +196,5 @@
* means.
*/
-int ntfs_umount(ntfs_volume *vol, const int force);
+BOOL ntfs_umount(ntfs_volume *vol, const int force);
#endif /* defined VOLUME_H */
|