void xfs_inode_set_eofblocks_tag( xfs_inode_t *ip) { struct xfs_mount *mp = ip->i_mount; struct xfs_perag *pag; int tagged; pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); spin_lock(&pag->pag_ici_lock); trace_xfs_inode_set_eofblocks_tag(ip); tagged = radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_EOFBLOCKS_TAG); radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), XFS_ICI_EOFBLOCKS_TAG); if (!tagged) { /* propagate the eofblocks tag up into the perag radix tree */ spin_lock(&ip->i_mount->m_perag_lock); radix_tree_tag_set(&ip->i_mount->m_perag_tree, XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), XFS_ICI_EOFBLOCKS_TAG); spin_unlock(&ip->i_mount->m_perag_lock); /* kick off background trimming */ xfs_queue_eofblocks(ip->i_mount); trace_xfs_perag_set_eofblocks(ip->i_mount, pag->pag_agno, -1, _RET_IP_); } spin_unlock(&pag->pag_ici_lock); xfs_perag_put(pag); }
void __xfs_inode_set_reclaim_tag( struct xfs_perag *pag, struct xfs_inode *ip) { radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), XFS_ICI_RECLAIM_TAG); if (!pag->pag_ici_reclaimable) { /* propagate the reclaim tag up into the perag radix tree */ spin_lock(&ip->i_mount->m_perag_lock); radix_tree_tag_set(&ip->i_mount->m_perag_tree, XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), XFS_ICI_RECLAIM_TAG); spin_unlock(&ip->i_mount->m_perag_lock); /* schedule periodic background inode reclaim */ xfs_syncd_queue_reclaim(ip->i_mount); trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno, -1, _RET_IP_); } pag->pag_ici_reclaimable++; }
void __xfs_inode_set_reclaim_tag( struct xfs_perag *pag, struct xfs_inode *ip) { radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), XFS_ICI_RECLAIM_TAG); if (!pag->pag_ici_reclaimable) { spin_lock(&ip->i_mount->m_perag_lock); radix_tree_tag_set(&ip->i_mount->m_perag_tree, XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), XFS_ICI_RECLAIM_TAG); spin_unlock(&ip->i_mount->m_perag_lock); xfs_syncd_queue_reclaim(ip->i_mount); trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno, -1, _RET_IP_); } pag->pag_ici_reclaimable++; }
int test_set_page_writeback(struct page *page) { struct address_space *mapping = page_mapping(page); int ret; if (mapping) { unsigned long flags; write_lock_irqsave(&mapping->tree_lock, flags); ret = TestSetPageWriteback(page); if (!ret) radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_WRITEBACK); if (!PageDirty(page)) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); write_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestSetPageWriteback(page); } if (!ret) inc_zone_page_state(page, NR_WRITEBACK); return ret; }
/** * nilfs_copy_back_pages -- copy back pages to original cache from shadow cache * @dmap: destination page cache * @smap: source page cache * * No pages must no be added to the cache during this process. * This must be ensured by the caller. */ void nilfs_copy_back_pages(struct address_space *dmap, struct address_space *smap) { struct pagevec pvec; unsigned int i, n; pgoff_t index = 0; int err; pagevec_init(&pvec); repeat: n = pagevec_lookup(&pvec, smap, &index); if (!n) return; for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i], *dpage; pgoff_t offset = page->index; lock_page(page); dpage = find_lock_page(dmap, offset); if (dpage) { /* override existing page on the destination cache */ WARN_ON(PageDirty(dpage)); nilfs_copy_page(dpage, page, 0); unlock_page(dpage); put_page(dpage); } else { struct page *page2; /* move the page to the destination cache */ spin_lock_irq(&smap->tree_lock); page2 = radix_tree_delete(&smap->page_tree, offset); WARN_ON(page2 != page); smap->nrpages--; spin_unlock_irq(&smap->tree_lock); spin_lock_irq(&dmap->tree_lock); err = radix_tree_insert(&dmap->page_tree, offset, page); if (unlikely(err < 0)) { WARN_ON(err == -EEXIST); page->mapping = NULL; put_page(page); /* for cache */ } else { page->mapping = dmap; dmap->nrpages++; if (PageDirty(page)) radix_tree_tag_set(&dmap->page_tree, offset, PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&dmap->tree_lock); } unlock_page(page); } pagevec_release(&pvec); cond_resched(); goto repeat; }
/* * For address_spaces which do not use buffers. Just tag the page as dirty in * its radix tree. * * This is also used when a single buffer is being dirtied: we want to set the * page dirty in that case, but not all the buffers. This is a "bottom-up" * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying. * * Most callers have locked the page, which pins the address_space in memory. * But zap_pte_range() does not lock the page, however in that case the * mapping is pinned by the vma's ->vm_file reference. * * We take care to handle the case where the page was truncated from the * mapping by re-checking page_mapping() inside tree_lock. */ int __set_page_dirty_nobuffers(struct page *page) { if (!TestSetPageDirty(page)) { struct address_space *mapping = page_mapping(page); struct address_space *mapping2; if (!mapping) return 1; spin_lock_irq(&mapping->tree_lock); mapping2 = page_mapping(page); if (mapping2) { /* Race with truncate? */ BUG_ON(mapping2 != mapping); WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page)); account_page_dirtied(page, mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&mapping->tree_lock); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } return 1; } return 0; }
static void __tux3_test_set_page_writeback(struct page *page, int old_writeback) { struct address_space *mapping = page->mapping; if (mapping) { struct backing_dev_info *bdi = mapping->backing_dev_info; unsigned long flags; spin_lock_irqsave(&mapping->tree_lock, flags); if (!old_writeback) { /* If PageForked(), don't touch tag */ if (!PageForked(page)) radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_WRITEBACK); if (bdi_cap_account_writeback(bdi)) __inc_bdi_stat(bdi, BDI_WRITEBACK); } /* If PageForked(), don't touch tag */ if (!PageDirty(page) && !PageForked(page)) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_TOWRITE); spin_unlock_irqrestore(&mapping->tree_lock, flags); } if (!old_writeback) { account_page_writeback(page); tux3_accout_set_writeback(page); } }
/* * Insert a write request into an inode */ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(inode); int error; error = radix_tree_preload(GFP_NOFS); if (error != 0) goto out; /* Lock the request! */ nfs_lock_request_dontget(req); spin_lock(&inode->i_lock); error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); BUG_ON(error); if (!nfsi->npages) { igrab(inode); if (nfs_have_delegation(inode, FMODE_WRITE)) nfsi->change_attr++; } SetPagePrivate(req->wb_page); set_page_private(req->wb_page, (unsigned long)req); nfsi->npages++; kref_get(&req->wb_kref); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); spin_unlock(&inode->i_lock); radix_tree_preload_end(); out: return error; }
int test_set_page_writeback(struct page *page) { struct address_space *mapping = page_mapping(page); int ret; if (mapping) { struct backing_dev_info *bdi = mapping->backing_dev_info; unsigned long flags; spin_lock_irqsave(&mapping->tree_lock, flags); ret = TestSetPageWriteback(page); if (!ret) { radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_WRITEBACK); if (bdi_cap_account_writeback(bdi)) __inc_bdi_stat(bdi, BDI_WRITEBACK); } if (!PageDirty(page)) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); spin_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestSetPageWriteback(page); } if (!ret) inc_zone_page_state(page, NR_WRITEBACK); return ret; }
/** * hwspin_lock_register() - register a new hw spinlock * @hwlock: hwspinlock to register. * * This function should be called from the underlying platform-specific * implementation, to register a new hwspinlock instance. * * Can be called from an atomic context (will not sleep) but not from * within interrupt context. * * Returns 0 on success, or an appropriate error code on failure */ int hwspin_lock_register(struct hwspinlock *hwlock) { struct hwspinlock *tmp; int ret; if (!hwlock || !hwlock->ops || !hwlock->ops->trylock || !hwlock->ops->unlock) { pr_err("invalid parameters\n"); return -EINVAL; } spin_lock_init(&hwlock->lock); spin_lock(&hwspinlock_tree_lock); ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock); if (ret) goto out; /* mark this hwspinlock as available */ tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id, HWSPINLOCK_UNUSED); /* self-sanity check which should never fail */ WARN_ON(tmp != hwlock); out: spin_unlock(&hwspinlock_tree_lock); return ret; }
/** * nfs_set_page_tag_locked - Tag a request as locked * @req: */ int nfs_set_page_tag_locked(struct nfs_page *req) { if (!nfs_lock_request_dontget(req)) return 0; if (req->wb_page != NULL) radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; }
/** * nfs_set_page_tag_locked - Tag a request as locked * @req: */ int nfs_set_page_tag_locked(struct nfs_page *req) { if (!nfs_lock_request_dontget(req)) return 0; if (test_bit(PG_MAPPED, &req->wb_flags)) radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; }
static void __xfs_inode_set_eofblocks_tag( xfs_inode_t *ip, void (*execute)(struct xfs_mount *mp), void (*set_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, int error, unsigned long caller_ip), int tag) { struct xfs_mount *mp = ip->i_mount; struct xfs_perag *pag; int tagged; /* * Don't bother locking the AG and looking up in the radix trees * if we already know that we have the tag set. */ if (ip->i_flags & XFS_IEOFBLOCKS) return; spin_lock(&ip->i_flags_lock); ip->i_flags |= XFS_IEOFBLOCKS; spin_unlock(&ip->i_flags_lock); pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); spin_lock(&pag->pag_ici_lock); tagged = radix_tree_tagged(&pag->pag_ici_root, tag); radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), tag); if (!tagged) { /* propagate the eofblocks tag up into the perag radix tree */ spin_lock(&ip->i_mount->m_perag_lock); radix_tree_tag_set(&ip->i_mount->m_perag_tree, XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), tag); spin_unlock(&ip->i_mount->m_perag_lock); /* kick off background trimming */ execute(ip->i_mount); set_tp(ip->i_mount, pag->pag_agno, -1, _RET_IP_); } spin_unlock(&pag->pag_ici_lock); xfs_perag_put(pag); }
/** * nfs_set_page_writeback_locked - Lock a request for writeback * @req: */ int nfs_set_page_writeback_locked(struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); if (!nfs_lock_request(req)) return 0; radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); return 1; }
/** * nfs_set_page_tag_locked - Tag a request as locked * @req: */ static int nfs_set_page_tag_locked(struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); if (!nfs_lock_request(req)) return 0; radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; }
/* * Copy of __set_page_dirty() without __mark_inode_dirty(). Caller * decides whether mark inode dirty or not. */ static void __tux3_set_page_dirty(struct page *page, struct address_space *mapping, int warn) { spin_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ WARN_ON_ONCE(warn && !PageUptodate(page)); account_page_dirtied(page, mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&mapping->tree_lock); }
/* * Copy of __set_page_dirty() without __mark_inode_dirty(). Caller * decides whether mark inode dirty or not. */ void __tux3_set_page_dirty_account(struct page *page, struct address_space *mapping, int warn) { unsigned long flags; spin_lock_irqsave(&mapping->tree_lock, flags); if (page->mapping) { /* Race with truncate? */ WARN_ON_ONCE(warn && !PageUptodate(page)); account_page_dirtied(page, mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } spin_unlock_irqrestore(&mapping->tree_lock, flags); }
/* * this does all the record keeping required to make sure that a reference * counted root is properly recorded in a given transaction. This is required * to make sure the old root from before we joined the transaction is deleted * when the transaction commits */ static noinline int record_root_in_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root) { if (root->ref_cows && root->last_trans < trans->transid) { WARN_ON(root == root->fs_info->extent_root); WARN_ON(root->commit_root != root->node); radix_tree_tag_set(&root->fs_info->fs_roots_radix, (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); root->last_trans = trans->transid; btrfs_init_reloc_root(trans, root); } return 0; }
/* * Add a request to the inode's commit list. */ static void nfs_mark_request_commit(struct nfs_page *req) { struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); set_bit(PG_CLEAN, &(req)->wb_flags); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_COMMIT); spin_unlock(&inode->i_lock); inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); __mark_inode_dirty(inode, I_DIRTY_DATASYNC); }
void regression2_test(void) { int i; struct page *p; int max_slots = RADIX_TREE_MAP_SIZE; unsigned long int start, end; struct page *pages[1]; printf("running regression test 2 (should take milliseconds)\n"); /* 0. */ for (i = 0; i <= max_slots - 1; i++) { p = page_alloc(); radix_tree_insert(&mt_tree, i, p); } radix_tree_tag_set(&mt_tree, max_slots - 1, PAGECACHE_TAG_DIRTY); /* 1. */ start = 0; end = max_slots - 2; radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1, PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); /* 2. */ p = page_alloc(); radix_tree_insert(&mt_tree, max_slots, p); /* 3. */ radix_tree_tag_clear(&mt_tree, max_slots - 1, PAGECACHE_TAG_DIRTY); /* 4. */ for (i = max_slots - 1; i >= 0; i--) radix_tree_delete(&mt_tree, i); /* 5. */ // NOTE: start should not be 0 because radix_tree_gang_lookup_tag_slot // can return. start = 1; end = max_slots - 2; radix_tree_gang_lookup_tag_slot(&mt_tree, (void ***)pages, start, end, PAGECACHE_TAG_TOWRITE); /* We remove all the remained nodes */ radix_tree_delete(&mt_tree, max_slots); printf("regression test 2, done\n"); }
/* * remove an extent from the root, returns 0 on success */ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 blocknr, u64 num_blocks, int pin) { struct btrfs_root *extent_root = root->fs_info->extent_root; struct btrfs_buffer *t; int pending_ret; int ret; if (root == extent_root) { t = find_tree_block(root, blocknr); radix_tree_tag_set(&root->fs_info->cache_radix, blocknr, CTREE_EXTENT_PENDING_DEL); return 0; } ret = __free_extent(trans, root, blocknr, num_blocks, pin); pending_ret = run_pending(trans, root->fs_info->extent_root); return ret ? ret : pending_ret; }
/* * We set the inode flag atomically with the radix tree tag. * Once we get tag lookups on the radix tree, this inode flag * can go away. */ void xfs_inode_set_reclaim_tag( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; struct xfs_perag *pag; pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); spin_lock(&pag->pag_ici_lock); spin_lock(&ip->i_flags_lock); radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); xfs_perag_set_reclaim_tag(pag); __xfs_iflags_set(ip, XFS_IRECLAIMABLE); spin_unlock(&ip->i_flags_lock); spin_unlock(&pag->pag_ici_lock); xfs_perag_put(pag); }
/* * this does all the record keeping required to make sure that a reference * counted root is properly recorded in a given transaction. This is required * to make sure the old root from before we joined the transaction is deleted * when the transaction commits */ noinline int btrfs_record_root_in_trans(struct btrfs_root *root) { struct btrfs_dirty_root *dirty; u64 running_trans_id = root->fs_info->running_transaction->transid; if (root->ref_cows && root->last_trans < running_trans_id) { WARN_ON(root == root->fs_info->extent_root); if (root->root_item.refs != 0) { radix_tree_tag_set(&root->fs_info->fs_roots_radix, (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); dirty = kmalloc(sizeof(*dirty), GFP_NOFS); BUG_ON(!dirty); dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS); BUG_ON(!dirty->root); dirty->latest_root = root; INIT_LIST_HEAD(&dirty->list); root->commit_root = btrfs_root_node(root); memcpy(dirty->root, root, sizeof(*root)); spin_lock_init(&dirty->root->node_lock); spin_lock_init(&dirty->root->list_lock); mutex_init(&dirty->root->objectid_mutex); mutex_init(&dirty->root->log_mutex); INIT_LIST_HEAD(&dirty->root->dead_list); dirty->root->node = root->commit_root; dirty->root->commit_root = NULL; spin_lock(&root->list_lock); list_add(&dirty->root->dead_list, &root->dead_list); spin_unlock(&root->list_lock); root->dirty_root = dirty; } else { WARN_ON(1); } root->last_trans = running_trans_id; } return 0; }
/** * hwspin_lock_free() - free a specific hwspinlock * @hwlock: the specific hwspinlock to free * * This function mark @hwlock as free again. * Should only be called with an @hwlock that was retrieved from * an earlier call to omap_hwspin_lock_request{_specific}. * * Should be called from a process context (might sleep) * * Returns 0 on success, or an appropriate error code on failure */ int hwspin_lock_free(struct hwspinlock *hwlock) { struct device *dev = hwlock->bank->dev; struct hwspinlock *tmp; int ret; if (!hwlock) { pr_err("invalid hwlock\n"); return -EINVAL; } mutex_lock(&hwspinlock_tree_lock); /* make sure the hwspinlock is used */ ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock), HWSPINLOCK_UNUSED); if (ret == 1) { dev_err(dev, "%s: hwlock is already free\n", __func__); dump_stack(); ret = -EINVAL; goto out; } /* notify the underlying device that power is not needed */ ret = pm_runtime_put(dev); if (ret < 0) goto out; /* mark this hwspinlock as available */ tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock), HWSPINLOCK_UNUSED); /* sanity check (this shouldn't happen) */ WARN_ON(tmp != hwlock); module_put(dev->driver->owner); out: mutex_unlock(&hwspinlock_tree_lock); return ret; }
static void xfs_perag_set_reclaim_tag( struct xfs_perag *pag) { struct xfs_mount *mp = pag->pag_mount; ASSERT(spin_is_locked(&pag->pag_ici_lock)); if (pag->pag_ici_reclaimable++) return; /* propagate the reclaim tag up into the perag radix tree */ spin_lock(&mp->m_perag_lock); radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno, XFS_ICI_RECLAIM_TAG); spin_unlock(&mp->m_perag_lock); /* schedule periodic background inode reclaim */ xfs_reclaim_work_queue(mp); trace_xfs_perag_set_reclaim(mp, pag->pag_agno, -1, _RET_IP_); }
/** * nilfs_btnode_commit_change_key * commit the change_key operation prepared by prepare_change_key(). */ void nilfs_btnode_commit_change_key(struct address_space *btnc, struct nilfs_btnode_chkey_ctxt *ctxt) { struct buffer_head *obh = ctxt->bh, *nbh = ctxt->newbh; __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey; struct page *opage; if (oldkey == newkey) return; if (nbh == NULL) { /* blocksize == pagesize */ opage = obh->b_page; if (unlikely(oldkey != opage->index)) NILFS_PAGE_BUG(opage, "invalid oldkey %lld (newkey=%lld)", (unsigned long long)oldkey, (unsigned long long)newkey); if (!test_set_buffer_dirty(obh) && TestSetPageDirty(opage)) BUG(); WRITE_LOCK_IRQ(&btnc->tree_lock); radix_tree_delete(&btnc->page_tree, oldkey); radix_tree_tag_set(&btnc->page_tree, newkey, PAGECACHE_TAG_DIRTY); WRITE_UNLOCK_IRQ(&btnc->tree_lock); opage->index = obh->b_blocknr = newkey; unlock_page(opage); } else { nilfs_copy_buffer(nbh, obh); nilfs_btnode_mark_dirty(nbh); nbh->b_blocknr = newkey; ctxt->bh = nbh; nilfs_btnode_delete(obh); /* will decrement bh->b_count */ } }
static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) { struct hwspinlock *tmp; int ret; mutex_lock(&hwspinlock_tree_lock); ret = radix_tree_insert(&hwspinlock_tree, id, hwlock); if (ret) { if (ret == -EEXIST) pr_err("hwspinlock id %d already exists!\n", id); goto out; } /* mark this hwspinlock as available */ tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); /* self-sanity check which should never fail */ WARN_ON(tmp != hwlock); out: mutex_unlock(&hwspinlock_tree_lock); return 0; }
void nilfs_btnode_commit_change_key(struct address_space *btnc, struct nilfs_btnode_chkey_ctxt *ctxt) { struct buffer_head *obh = ctxt->bh, *nbh = ctxt->newbh; __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey; struct page *opage; if (oldkey == newkey) return; if (nbh == NULL) { opage = obh->b_page; if (unlikely(oldkey != opage->index)) NILFS_PAGE_BUG(opage, "invalid oldkey %lld (newkey=%lld)", (unsigned long long)oldkey, (unsigned long long)newkey); mark_buffer_dirty(obh); spin_lock_irq(&btnc->tree_lock); radix_tree_delete(&btnc->page_tree, oldkey); radix_tree_tag_set(&btnc->page_tree, newkey, PAGECACHE_TAG_DIRTY); spin_unlock_irq(&btnc->tree_lock); opage->index = obh->b_blocknr = newkey; unlock_page(opage); } else { nilfs_copy_buffer(nbh, obh); mark_buffer_dirty(nbh); nbh->b_blocknr = newkey; ctxt->bh = nbh; nilfs_btnode_delete(obh); } }
static int update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 blocknr, u64 num, int alloc) { struct btrfs_block_group_cache *cache; struct btrfs_fs_info *info = root->fs_info; u64 total = num; u64 old_val; u64 block_in_group; int ret; while(total) { ret = radix_tree_gang_lookup(&info->block_group_radix, (void **)&cache, blocknr, 1); if (!ret) return -1; radix_tree_tag_set(&info->block_group_radix, cache->key.objectid + cache->key.offset - 1, BTRFS_BLOCK_GROUP_DIRTY); block_in_group = blocknr - cache->key.objectid; old_val = btrfs_block_group_used(&cache->item); if (total > cache->key.offset - block_in_group) num = cache->key.offset - block_in_group; else num = total; total -= num; blocknr += num; if (alloc) old_val += num; else old_val -= num; btrfs_set_block_group_used(&cache->item, old_val); } return 0; }
/** * write_one_page - write out a single page and optionally wait on I/O * @page: the page to write * @wait: if true, wait on writeout * * The page must be locked by the caller and will be unlocked upon return. * * write_one_page() returns a negative error code if I/O failed. */ int write_one_page(struct page *page, int wait) { struct address_space *mapping = page->mapping; int ret = 0; struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, .nr_to_write = 1, }; BUG_ON(!PageLocked(page)); if (wait) wait_on_page_writeback(page); if (clear_page_dirty_for_io(page)) { page_cache_get(page); ret = mapping->a_ops->writepage(page, &wbc); if (ret == 0 && wait) { wait_on_page_writeback(page); if (PageError(page)) ret = -EIO; } page_cache_release(page); } else { unlock_page(page); } return ret; } EXPORT_SYMBOL(write_one_page); /* * For address_spaces which do not use buffers nor write back. */ int __set_page_dirty_no_writeback(struct page *page) { if (!PageDirty(page)) SetPageDirty(page); return 0; } /* * For address_spaces which do not use buffers. Just tag the page as dirty in * its radix tree. * * This is also used when a single buffer is being dirtied: we want to set the * page dirty in that case, but not all the buffers. This is a "bottom-up" * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying. * * Most callers have locked the page, which pins the address_space in memory. * But zap_pte_range() does not lock the page, however in that case the * mapping is pinned by the vma's ->vm_file reference. * * We take care to handle the case where the page was truncated from the * mapping by re-checking page_mapping() inside tree_lock. */ int __set_page_dirty_nobuffers(struct page *page) { if (!TestSetPageDirty(page)) { struct address_space *mapping = page_mapping(page); struct address_space *mapping2; if (!mapping) return 1; spin_lock_irq(&mapping->tree_lock); mapping2 = page_mapping(page); if (mapping2) { /* Race with truncate? */ BUG_ON(mapping2 != mapping); WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page)); if (mapping_cap_account_dirty(mapping)) { __inc_zone_page_state(page, NR_FILE_DIRTY); __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE); task_io_account_write(PAGE_CACHE_SIZE); } radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&mapping->tree_lock); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } return 1; } return 0; } EXPORT_SYMBOL(__set_page_dirty_nobuffers); /* * When a writepage implementation decides that it doesn't want to write this * page for some reason, it should redirty the locked page via * redirty_page_for_writepage() and it should then unlock the page and return 0 */ int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page) { wbc->pages_skipped++; return __set_page_dirty_nobuffers(page); }