From b6ad6c52fe36ab35d0fe28c064f59de2ba670c2a Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Tue, 15 Feb 2005 10:08:43 +0000 Subject: NTFS: - Split ntfs_map_runlist() into ntfs_map_runlist() and a non-locking helper ntfs_map_runlist_nolock() which is used by ntfs_map_runlist(). This allows us to map runlist fragments with the runlist lock already held without having to drop and reacquire it around the call. Adapt all callers. - Change ntfs_find_vcn() to ntfs_find_vcn_nolock() which takes a locked runlist. This allows us to find runlist elements with the runlist lock already held without having to drop and reacquire it around the call. Adapt all callers. Signed-off-by: Anton Altaparmakov --- fs/ntfs/attrib.c | 107 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 45 deletions(-) (limited to 'fs/ntfs/attrib.c') diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 7d668466dcd..7a16f7ca76d 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1,7 +1,7 @@ /** * attrib.c - NTFS attribute operations. 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 @@ -30,7 +30,7 @@ #include "types.h" /** - * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode + * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode * @ni: ntfs inode for which to map (part of) a runlist * @vcn: map runlist part containing this vcn * @@ -38,24 +38,23 @@ * * Return 0 on success and -errno on error. * - * Locking: - The runlist must be unlocked on entry and is unlocked on return. - * - This function takes the lock for writing and modifies the runlist. + * Locking: - The runlist must be locked for writing. + * - This function modifies the runlist. */ -int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) +int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) { ntfs_inode *base_ni; - ntfs_attr_search_ctx *ctx; MFT_RECORD *mrec; + ntfs_attr_search_ctx *ctx; + runlist_element *rl; int err = 0; ntfs_debug("Mapping runlist part containing vcn 0x%llx.", (unsigned long long)vcn); - if (!NInoAttr(ni)) base_ni = ni; else base_ni = ni->ext.base_ntfs_ino; - mrec = map_mft_record(base_ni); if (IS_ERR(mrec)) return PTR_ERR(mrec); @@ -66,15 +65,7 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) } err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, vcn, NULL, 0, ctx); - if (unlikely(err)) - goto put_err_out; - - down_write(&ni->runlist.lock); - /* Make sure someone else didn't do the work while we were sleeping. */ - if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= - LCN_RL_NOT_MAPPED)) { - runlist_element *rl; - + if (likely(!err)) { rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, ni->runlist.rl); if (IS_ERR(rl)) @@ -82,9 +73,6 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) else ni->runlist.rl = rl; } - up_write(&ni->runlist.lock); - -put_err_out: ntfs_attr_put_search_ctx(ctx); err_out: unmap_mft_record(base_ni); @@ -92,17 +80,45 @@ err_out: } /** - * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode - * @ni: ntfs inode describing the runlist to search - * @vcn: vcn to find - * @need_write: if false, lock for reading and if true, lock for writing + * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode + * @ni: ntfs inode for which to map (part of) a runlist + * @vcn: map runlist part containing this vcn + * + * Map the part of a runlist containing the @vcn of the ntfs inode @ni. + * + * Return 0 on success and -errno on error. + * + * Locking: - The runlist must be unlocked on entry and is unlocked on return. + * - This function takes the runlist lock for writing and modifies the + * runlist. + */ +int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) +{ + int err = 0; + + down_write(&ni->runlist.lock); + /* Make sure someone else didn't do the work while we were sleeping. */ + if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= + LCN_RL_NOT_MAPPED)) + err = ntfs_map_runlist_nolock(ni, vcn); + up_write(&ni->runlist.lock); + return err; +} + +/** + * 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 + * @write_locked: true if the runlist is locked for writing * * Find the virtual cluster number @vcn in the runlist described by the ntfs * inode @ni and return the address of the runlist element containing the @vcn. - * The runlist is left locked and the caller has to unlock it. If @need_write - * is true, the runlist is locked for writing and if @need_write is false, the - * runlist is locked for reading. In the error case, the runlist is not left - * locked. + * The runlist is left locked and the caller has to unlock it. In the error + * case, the runlist is left in the same locking state as on entry. + * + * Note if @write_locked is FALSE the lock may be dropped inside the function + * so you cannot rely on the runlist still being the same when this function + * returns. * * Note you need to distinguish between the lcn of the returned runlist element * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on @@ -124,28 +140,24 @@ err_out: * true, it is locked for writing. Otherwise is is locked for * reading. */ -runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, - const BOOL need_write) +runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, + const BOOL write_locked) { runlist_element *rl; int err = 0; BOOL is_retry = FALSE; - ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.", + ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", ni->mft_no, (unsigned long long)vcn, - !need_write ? "read" : "writ"); + write_locked ? "write" : "read"); BUG_ON(!ni); BUG_ON(!NInoNonResident(ni)); BUG_ON(vcn < 0); -lock_retry_remap: - if (!need_write) - down_read(&ni->runlist.lock); - else - down_write(&ni->runlist.lock); +retry_remap: rl = ni->runlist.rl; if (likely(rl && vcn >= rl[0].vcn)) { while (likely(rl->length)) { - if (likely(vcn < rl[1].vcn)) { + if (unlikely(vcn < rl[1].vcn)) { if (likely(rl->lcn >= LCN_HOLE)) { ntfs_debug("Done."); return rl; @@ -161,19 +173,23 @@ lock_retry_remap: err = -EIO; } } - if (!need_write) - up_read(&ni->runlist.lock); - else - up_write(&ni->runlist.lock); if (!err && !is_retry) { /* * The @vcn is in an unmapped region, map the runlist and * retry. */ - err = ntfs_map_runlist(ni, vcn); + if (!write_locked) { + up_read(&ni->runlist.lock); + down_write(&ni->runlist.lock); + } + 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 lock_retry_remap; + goto retry_remap; } /* * -EINVAL and -ENOENT coming from a failed mapping attempt are @@ -184,7 +200,8 @@ lock_retry_remap: err = -EIO; } else if (!err) err = -EIO; - ntfs_error(ni->vol->sb, "Failed with error code %i.", err); + if (err != -ENOENT) + ntfs_error(ni->vol->sb, "Failed with error code %i.", err); return ERR_PTR(err); } -- cgit v1.2.3