NTFS: Add fs/ntfs/attrib.[hc]::ntfs_attr_vcn_to_lcn_nolock() used by the new
Anton Altaparmakov [Mon, 7 Mar 2005 21:36:18 +0000 (21:36 +0000)]
      write code.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>

fs/ntfs/ChangeLog
fs/ntfs/attrib.c
fs/ntfs/attrib.h

index 868871c..4af6ae6 100644 (file)
@@ -88,8 +88,10 @@ ToDo/Notes:
          checked and set in the ntfs inode as done for compressed files and
          the compressed size needs to be used for vfs inode->i_blocks instead
          of the allocated size, again, as done for compressed files.
-       - Add AT_EA in addition to AT_DATA to whitelist for being allowed to
-         be non-resident in fs/ntfs/attrib.c::ntfs_attr_can_be_non_resident().
+       - Add AT_EA in addition to AT_DATA to whitelist for being allowed to be
+         non-resident in fs/ntfs/attrib.c::ntfs_attr_can_be_non_resident().
+       - Add fs/ntfs/attrib.c::ntfs_attr_vcn_to_lcn_nolock() used by the new
+         write code.
 
 2.1.22 - Many bug and race fixes and error handling improvements.
 
index fa464fc..1610f1c 100644 (file)
@@ -106,6 +106,93 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn)
 }
 
 /**
+ * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode
+ * @ni:                        ntfs inode of the attribute whose runlist to search
+ * @vcn:               vcn to convert
+ * @write_locked:      true if the runlist is locked for writing
+ *
+ * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
+ * described by the ntfs inode @ni and return the corresponding logical cluster
+ * number (lcn).
+ *
+ * If the @vcn is not mapped yet, the attempt is made to map the attribute
+ * extent containing the @vcn and the vcn to lcn conversion is retried.
+ *
+ * If @write_locked is true the caller has locked the runlist for writing and
+ * if false for reading.
+ *
+ * Since lcns must be >= 0, we use negative return codes with special meaning:
+ *
+ * Return code Meaning / Description
+ * ==========================================
+ *  LCN_HOLE   Hole / not allocated on disk.
+ *  LCN_ENOENT There is no such vcn in the runlist, i.e. @vcn is out of bounds.
+ *  LCN_ENOMEM Not enough memory to map runlist.
+ *  LCN_EIO    Critical error (runlist/file is corrupt, i/o error, etc).
+ *
+ * Locking: - The runlist must be locked on entry and is left locked on return.
+ *         - If @write_locked is FALSE, i.e. the runlist is locked for reading,
+ *           the lock may be dropped inside the function so you cannot rely on
+ *           the runlist still being the same when this function returns.
+ */
+LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
+               const BOOL write_locked)
+{
+       LCN lcn;
+       BOOL is_retry = FALSE;
+
+       ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
+                       ni->mft_no, (unsigned long long)vcn,
+                       write_locked ? "write" : "read");
+       BUG_ON(!ni);
+       BUG_ON(!NInoNonResident(ni));
+       BUG_ON(vcn < 0);
+retry_remap:
+       /* Convert vcn to lcn.  If that fails map the runlist and retry once. */
+       lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn);
+       if (likely(lcn >= LCN_HOLE)) {
+               ntfs_debug("Done, lcn 0x%llx.", (long long)lcn);
+               return lcn;
+       }
+       if (lcn != LCN_RL_NOT_MAPPED) {
+               if (lcn != LCN_ENOENT)
+                       lcn = LCN_EIO;
+       } else if (!is_retry) {
+               int err;
+
+               if (!write_locked) {
+                       up_read(&ni->runlist.lock);
+                       down_write(&ni->runlist.lock);
+                       if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
+                                       LCN_RL_NOT_MAPPED)) {
+                               up_write(&ni->runlist.lock);
+                               down_read(&ni->runlist.lock);
+                               goto retry_remap;
+                       }
+               }
+               err = ntfs_map_runlist_nolock(ni, vcn);
+               if (!write_locked) {
+                       up_write(&ni->runlist.lock);
+                       down_read(&ni->runlist.lock);
+               }
+               if (likely(!err)) {
+                       is_retry = TRUE;
+                       goto retry_remap;
+               }
+               if (err == -ENOENT)
+                       lcn = LCN_ENOENT;
+               else if (err == -ENOMEM)
+                       lcn = LCN_ENOMEM;
+               else
+                       lcn = LCN_EIO;
+       }
+       if (lcn != LCN_ENOENT)
+               ntfs_error(ni->vol->sb, "Failed with error code %lli.",
+                               (long long)lcn);
+       return lcn;
+}
+
+/**
  * ntfs_find_vcn_nolock - find a vcn in the runlist described by an ntfs inode
  * @ni:                        ntfs inode describing the runlist to search
  * @vcn:               vcn to find
index 3eb4516..75041c8 100644 (file)
@@ -2,7 +2,7 @@
  * attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
  *           Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2001-2005 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -63,6 +63,9 @@ typedef struct {
 extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn);
 extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
 
+extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
+               const BOOL write_locked);
+
 extern runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
                const BOOL write_locked);