Commit 8b5baa46 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw

Pull gfs2 updates from Steven Whitehouse:
 "The main feature of interest this time is quota updates.  There are
  some clean ups and some patches to use the new generic lru list code.

  There is still plenty of scope for some further changes in due course -
  faster lookups of quota structures is very much on the todo list.
  Also, a start has been made towards the more tricky issue of using the
  generic lru code with glocks, but that will have to be completed in a
  subsequent merge window.

  The other, more minor feature, is that there have been a number of
  performance patches which relate to block allocation.  In particular
  they will improve performance when the disk is nearly full"

* tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw:
  GFS2: Use generic list_lru for quota
  GFS2: Rename quota qd_lru_lock qd_lock
  GFS2: Use reflink for quota data cache
  GFS2: Use lockref for glocks
  GFS2: Protect quota sync generation
  GFS2: Inline qd_trylock into gfs2_quota_unlock
  GFS2: Make two similar quota code fragments into a function
  GFS2: Remove obsolete quota tunable
  GFS2: Move gfs2_icbit_munge into quota.c
  GFS2: Speed up starting point selection for block allocation
  GFS2: Add allocation parameters structure
  GFS2: Clean up reservation removal
  GFS2: fix dentry leaks
  GFS2: new function gfs2_rbm_incr
  GFS2: Introduce rbm field bii
  GFS2: Do not reset flags on active reservations
  GFS2: introduce bi_blocks for optimization
  GFS2: optimize rbm_from_block wrt bi_start
  GFS2: d_splice_alias() can't return error
parents 6c86ae29 2147dbfd
...@@ -611,12 +611,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, ...@@ -611,12 +611,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
if (alloc_required) { if (alloc_required) {
struct gfs2_alloc_parms ap = { .aflags = 0, };
error = gfs2_quota_lock_check(ip); error = gfs2_quota_lock_check(ip);
if (error) if (error)
goto out_unlock; goto out_unlock;
requested = data_blocks + ind_blocks; requested = data_blocks + ind_blocks;
error = gfs2_inplace_reserve(ip, requested, 0); ap.target = requested;
error = gfs2_inplace_reserve(ip, &ap);
if (error) if (error)
goto out_qunlock; goto out_qunlock;
} }
......
...@@ -1216,6 +1216,7 @@ static int do_grow(struct inode *inode, u64 size) ...@@ -1216,6 +1216,7 @@ static int do_grow(struct inode *inode, u64 size)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_alloc_parms ap = { .target = 1, };
struct buffer_head *dibh; struct buffer_head *dibh;
int error; int error;
int unstuff = 0; int unstuff = 0;
...@@ -1226,7 +1227,7 @@ static int do_grow(struct inode *inode, u64 size) ...@@ -1226,7 +1227,7 @@ static int do_grow(struct inode *inode, u64 size)
if (error) if (error)
return error; return error;
error = gfs2_inplace_reserve(ip, 1, 0); error = gfs2_inplace_reserve(ip, &ap);
if (error) if (error)
goto do_grow_qunlock; goto do_grow_qunlock;
unstuff = 1; unstuff = 1;
...@@ -1279,6 +1280,7 @@ static int do_grow(struct inode *inode, u64 size) ...@@ -1279,6 +1280,7 @@ static int do_grow(struct inode *inode, u64 size)
int gfs2_setattr_size(struct inode *inode, u64 newsize) int gfs2_setattr_size(struct inode *inode, u64 newsize)
{ {
struct gfs2_inode *ip = GFS2_I(inode);
int ret; int ret;
u64 oldsize; u64 oldsize;
...@@ -1294,7 +1296,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) ...@@ -1294,7 +1296,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
inode_dio_wait(inode); inode_dio_wait(inode);
ret = gfs2_rs_alloc(GFS2_I(inode)); ret = gfs2_rs_alloc(ip);
if (ret) if (ret)
goto out; goto out;
...@@ -1304,6 +1306,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) ...@@ -1304,6 +1306,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
goto out; goto out;
} }
gfs2_rs_deltree(ip->i_res);
ret = do_shrink(inode, oldsize, newsize); ret = do_shrink(inode, oldsize, newsize);
out: out:
put_write_access(inode); put_write_access(inode);
......
...@@ -383,6 +383,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -383,6 +383,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
struct inode *inode = file_inode(vma->vm_file); struct inode *inode = file_inode(vma->vm_file);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_alloc_parms ap = { .aflags = 0, };
unsigned long last_index; unsigned long last_index;
u64 pos = page->index << PAGE_CACHE_SHIFT; u64 pos = page->index << PAGE_CACHE_SHIFT;
unsigned int data_blocks, ind_blocks, rblocks; unsigned int data_blocks, ind_blocks, rblocks;
...@@ -430,7 +431,8 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -430,7 +431,8 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
if (ret) if (ret)
goto out_unlock; goto out_unlock;
gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
ret = gfs2_inplace_reserve(ip, data_blocks + ind_blocks, 0); ap.target = data_blocks + ind_blocks;
ret = gfs2_inplace_reserve(ip, &ap);
if (ret) if (ret)
goto out_quota_unlock; goto out_quota_unlock;
...@@ -620,7 +622,7 @@ static int gfs2_release(struct inode *inode, struct file *file) ...@@ -620,7 +622,7 @@ static int gfs2_release(struct inode *inode, struct file *file)
if (!(file->f_mode & FMODE_WRITE)) if (!(file->f_mode & FMODE_WRITE))
return 0; return 0;
gfs2_rs_delete(ip); gfs2_rs_delete(ip, &inode->i_writecount);
return 0; return 0;
} }
...@@ -800,6 +802,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, ...@@ -800,6 +802,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_alloc_parms ap = { .aflags = 0, };
unsigned int data_blocks = 0, ind_blocks = 0, rblocks; unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
loff_t bytes, max_bytes; loff_t bytes, max_bytes;
int error; int error;
...@@ -850,7 +853,8 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, ...@@ -850,7 +853,8 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
retry: retry:
gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks); gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
error = gfs2_inplace_reserve(ip, data_blocks + ind_blocks, 0); ap.target = data_blocks + ind_blocks;
error = gfs2_inplace_reserve(ip, &ap);
if (error) { if (error) {
if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
bytes >>= 1; bytes >>= 1;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include <linux/lockref.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -129,10 +130,10 @@ void gfs2_glock_free(struct gfs2_glock *gl) ...@@ -129,10 +130,10 @@ void gfs2_glock_free(struct gfs2_glock *gl)
* *
*/ */
void gfs2_glock_hold(struct gfs2_glock *gl) static void gfs2_glock_hold(struct gfs2_glock *gl)
{ {
GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); GLOCK_BUG_ON(gl, __lockref_is_dead(&gl->gl_lockref));
atomic_inc(&gl->gl_ref); lockref_get(&gl->gl_lockref);
} }
/** /**
...@@ -186,20 +187,6 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) ...@@ -186,20 +187,6 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
spin_unlock(&lru_lock); spin_unlock(&lru_lock);
} }
/**
* gfs2_glock_put_nolock() - Decrement reference count on glock
* @gl: The glock to put
*
* This function should only be used if the caller has its own reference
* to the glock, in addition to the one it is dropping.
*/
void gfs2_glock_put_nolock(struct gfs2_glock *gl)
{
if (atomic_dec_and_test(&gl->gl_ref))
GLOCK_BUG_ON(gl, 1);
}
/** /**
* gfs2_glock_put() - Decrement reference count on glock * gfs2_glock_put() - Decrement reference count on glock
* @gl: The glock to put * @gl: The glock to put
...@@ -211,17 +198,22 @@ void gfs2_glock_put(struct gfs2_glock *gl) ...@@ -211,17 +198,22 @@ void gfs2_glock_put(struct gfs2_glock *gl)
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
struct address_space *mapping = gfs2_glock2aspace(gl); struct address_space *mapping = gfs2_glock2aspace(gl);
if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) { if (lockref_put_or_lock(&gl->gl_lockref))
__gfs2_glock_remove_from_lru(gl); return;
spin_unlock(&lru_lock);
spin_lock_bucket(gl->gl_hash); lockref_mark_dead(&gl->gl_lockref);
hlist_bl_del_rcu(&gl->gl_list);
spin_unlock_bucket(gl->gl_hash); spin_lock(&lru_lock);
GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); __gfs2_glock_remove_from_lru(gl);
GLOCK_BUG_ON(gl, mapping && mapping->nrpages); spin_unlock(&lru_lock);
trace_gfs2_glock_put(gl); spin_unlock(&gl->gl_lockref.lock);
sdp->sd_lockstruct.ls_ops->lm_put_lock(gl); spin_lock_bucket(gl->gl_hash);
} hlist_bl_del_rcu(&gl->gl_list);
spin_unlock_bucket(gl->gl_hash);
GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
GLOCK_BUG_ON(gl, mapping && mapping->nrpages);
trace_gfs2_glock_put(gl);
sdp->sd_lockstruct.ls_ops->lm_put_lock(gl);
} }
/** /**
...@@ -244,7 +236,7 @@ static struct gfs2_glock *search_bucket(unsigned int hash, ...@@ -244,7 +236,7 @@ static struct gfs2_glock *search_bucket(unsigned int hash,
continue; continue;
if (gl->gl_sbd != sdp) if (gl->gl_sbd != sdp)
continue; continue;
if (atomic_inc_not_zero(&gl->gl_ref)) if (lockref_get_not_dead(&gl->gl_lockref))
return gl; return gl;
} }
...@@ -396,10 +388,11 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) ...@@ -396,10 +388,11 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
held2 = (new_state != LM_ST_UNLOCKED); held2 = (new_state != LM_ST_UNLOCKED);
if (held1 != held2) { if (held1 != held2) {
GLOCK_BUG_ON(gl, __lockref_is_dead(&gl->gl_lockref));
if (held2) if (held2)
gfs2_glock_hold(gl); gl->gl_lockref.count++;
else else
gfs2_glock_put_nolock(gl); gl->gl_lockref.count--;
} }
if (held1 && held2 && list_empty(&gl->gl_holders)) if (held1 && held2 && list_empty(&gl->gl_holders))
clear_bit(GLF_QUEUED, &gl->gl_flags); clear_bit(GLF_QUEUED, &gl->gl_flags);
...@@ -626,9 +619,9 @@ __acquires(&gl->gl_spin) ...@@ -626,9 +619,9 @@ __acquires(&gl->gl_spin)
out_sched: out_sched:
clear_bit(GLF_LOCK, &gl->gl_flags); clear_bit(GLF_LOCK, &gl->gl_flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
gfs2_glock_hold(gl); gl->gl_lockref.count++;
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put_nolock(gl); gl->gl_lockref.count--;
return; return;
out_unlock: out_unlock:
...@@ -754,7 +747,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, ...@@ -754,7 +747,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_sbd = sdp; gl->gl_sbd = sdp;
gl->gl_flags = 0; gl->gl_flags = 0;
gl->gl_name = name; gl->gl_name = name;
atomic_set(&gl->gl_ref, 1); gl->gl_lockref.count = 1;
gl->gl_state = LM_ST_UNLOCKED; gl->gl_state = LM_ST_UNLOCKED;
gl->gl_target = LM_ST_UNLOCKED; gl->gl_target = LM_ST_UNLOCKED;
gl->gl_demote_state = LM_ST_EXCLUSIVE; gl->gl_demote_state = LM_ST_EXCLUSIVE;
...@@ -1356,10 +1349,10 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) ...@@ -1356,10 +1349,10 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
} }
} }
spin_unlock(&gl->gl_spin); gl->gl_lockref.count++;
set_bit(GLF_REPLY_PENDING, &gl->gl_flags); set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
smp_wmb(); spin_unlock(&gl->gl_spin);
gfs2_glock_hold(gl);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put(gl); gfs2_glock_put(gl);
} }
...@@ -1404,15 +1397,19 @@ __acquires(&lru_lock) ...@@ -1404,15 +1397,19 @@ __acquires(&lru_lock)
while(!list_empty(list)) { while(!list_empty(list)) {
gl = list_entry(list->next, struct gfs2_glock, gl_lru); gl = list_entry(list->next, struct gfs2_glock, gl_lru);
list_del_init(&gl->gl_lru); list_del_init(&gl->gl_lru);
if (!spin_trylock(&gl->gl_spin)) {
list_add(&gl->gl_lru, &lru_list);
atomic_inc(&lru_count);
continue;
}
clear_bit(GLF_LRU, &gl->gl_flags); clear_bit(GLF_LRU, &gl->gl_flags);
gfs2_glock_hold(gl);
spin_unlock(&lru_lock); spin_unlock(&lru_lock);
spin_lock(&gl->gl_spin); gl->gl_lockref.count++;
if (demote_ok(gl)) if (demote_ok(gl))
handle_callback(gl, LM_ST_UNLOCKED, 0, false); handle_callback(gl, LM_ST_UNLOCKED, 0, false);
WARN_ON(!test_and_clear_bit(GLF_LOCK, &gl->gl_flags)); WARN_ON(!test_and_clear_bit(GLF_LOCK, &gl->gl_flags));
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put_nolock(gl); gl->gl_lockref.count--;
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
spin_lock(&lru_lock); spin_lock(&lru_lock);
} }
...@@ -1493,7 +1490,7 @@ static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp, ...@@ -1493,7 +1490,7 @@ static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp,
rcu_read_lock(); rcu_read_lock();
hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) { hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) {
if ((gl->gl_sbd == sdp) && atomic_inc_not_zero(&gl->gl_ref)) if ((gl->gl_sbd == sdp) && lockref_get_not_dead(&gl->gl_lockref))
examiner(gl); examiner(gl);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -1746,7 +1743,7 @@ int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) ...@@ -1746,7 +1743,7 @@ int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
state2str(gl->gl_demote_state), dtime, state2str(gl->gl_demote_state), dtime,
atomic_read(&gl->gl_ail_count), atomic_read(&gl->gl_ail_count),
atomic_read(&gl->gl_revokes), atomic_read(&gl->gl_revokes),
atomic_read(&gl->gl_ref), gl->gl_hold_time); (int)gl->gl_lockref.count, gl->gl_hold_time);
list_for_each_entry(gh, &gl->gl_holders, gh_list) { list_for_each_entry(gh, &gl->gl_holders, gh_list) {
error = dump_holder(seq, gh); error = dump_holder(seq, gh);
...@@ -1902,7 +1899,7 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) ...@@ -1902,7 +1899,7 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
gi->nhash = 0; gi->nhash = 0;
} }
/* Skip entries for other sb and dead entries */ /* Skip entries for other sb and dead entries */
} while (gi->sdp != gi->gl->gl_sbd || atomic_read(&gi->gl->gl_ref) == 0); } while (gi->sdp != gi->gl->gl_sbd || __lockref_is_dead(&gl->gl_lockref));
return 0; return 0;
} }
......
...@@ -181,8 +181,6 @@ static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl) ...@@ -181,8 +181,6 @@ static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl)
extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
const struct gfs2_glock_operations *glops, const struct gfs2_glock_operations *glops,
int create, struct gfs2_glock **glp); int create, struct gfs2_glock **glp);
extern void gfs2_glock_hold(struct gfs2_glock *gl);
extern void gfs2_glock_put_nolock(struct gfs2_glock *gl);
extern void gfs2_glock_put(struct gfs2_glock *gl); extern void gfs2_glock_put(struct gfs2_glock *gl);
extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state,
unsigned flags, struct gfs2_holder *gh); unsigned flags, struct gfs2_holder *gh);
......
...@@ -525,9 +525,9 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote) ...@@ -525,9 +525,9 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
if (gl->gl_demote_state == LM_ST_UNLOCKED && if (gl->gl_demote_state == LM_ST_UNLOCKED &&
gl->gl_state == LM_ST_SHARED && ip) { gl->gl_state == LM_ST_SHARED && ip) {
gfs2_glock_hold(gl); gl->gl_lockref.count++;
if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0) if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
gfs2_glock_put_nolock(gl); gl->gl_lockref.count--;
} }
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/lockref.h>
#define DIO_WAIT 0x00000010 #define DIO_WAIT 0x00000010
#define DIO_METADATA 0x00000020 #define DIO_METADATA 0x00000020
...@@ -71,6 +72,7 @@ struct gfs2_bitmap { ...@@ -71,6 +72,7 @@ struct gfs2_bitmap {
u32 bi_offset; u32 bi_offset;
u32 bi_start; u32 bi_start;
u32 bi_len; u32 bi_len;
u32 bi_blocks;
}; };
struct gfs2_rgrpd { struct gfs2_rgrpd {
...@@ -101,19 +103,25 @@ struct gfs2_rgrpd { ...@@ -101,19 +103,25 @@ struct gfs2_rgrpd {
struct gfs2_rbm { struct gfs2_rbm {
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_bitmap *bi; /* Bitmap must belong to the rgd */
u32 offset; /* The offset is bitmap relative */ u32 offset; /* The offset is bitmap relative */
int bii; /* Bitmap index */
}; };
static inline struct gfs2_bitmap *rbm_bi(const struct gfs2_rbm *rbm)
{
return rbm->rgd->rd_bits + rbm->bii;
}
static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm) static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
{ {
return rbm->rgd->rd_data0 + (rbm->bi->bi_start * GFS2_NBBY) + rbm->offset; return rbm->rgd->rd_data0 + (rbm_bi(rbm)->bi_start * GFS2_NBBY) +
rbm->offset;
} }
static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1, static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1,
const struct gfs2_rbm *rbm2) const struct gfs2_rbm *rbm2)
{ {
return (rbm1->rgd == rbm2->rgd) && (rbm1->bi == rbm2->bi) && return (rbm1->rgd == rbm2->rgd) && (rbm1->bii == rbm2->bii) &&
(rbm1->offset == rbm2->offset); (rbm1->offset == rbm2->offset);
} }
...@@ -278,6 +286,20 @@ struct gfs2_blkreserv { ...@@ -278,6 +286,20 @@ struct gfs2_blkreserv {
unsigned int rs_qa_qd_num; unsigned int rs_qa_qd_num;
}; };
/*
* Allocation parameters
* @target: The number of blocks we'd ideally like to allocate
* @aflags: The flags (e.g. Orlov flag)
*
* The intent is to gradually expand this structure over time in
* order to give more information, e.g. alignment, min extent size
* to the allocation code.
*/
struct gfs2_alloc_parms {
u32 target;
u32 aflags;
};
enum { enum {
GLF_LOCK = 1, GLF_LOCK = 1,
GLF_DEMOTE = 3, GLF_DEMOTE = 3,
...@@ -300,9 +322,9 @@ struct gfs2_glock { ...@@ -300,9 +322,9 @@ struct gfs2_glock {
struct gfs2_sbd *gl_sbd; struct gfs2_sbd *gl_sbd;
unsigned long gl_flags; /* GLF_... */ unsigned long gl_flags; /* GLF_... */
struct lm_lockname gl_name; struct lm_lockname gl_name;
atomic_t gl_ref;
spinlock_t gl_spin; struct lockref gl_lockref;
#define gl_spin gl_lockref.lock
/* State fields protected by gl_spin */ /* State fields protected by gl_spin */
unsigned int gl_state:2, /* Current state */ unsigned int gl_state:2, /* Current state */
...@@ -398,11 +420,10 @@ enum { ...@@ -398,11 +420,10 @@ enum {
struct gfs2_quota_data { struct gfs2_quota_data {
struct list_head qd_list; struct list_head qd_list;
struct list_head qd_reclaim;
atomic_t qd_count;
struct kqid qd_id; struct kqid qd_id;
struct lockref qd_lockref;
struct list_head qd_lru;
unsigned long qd_flags; /* QDF_... */ unsigned long qd_flags; /* QDF_... */
s64 qd_change; s64 qd_change;
...@@ -516,7 +537,6 @@ struct gfs2_tune { ...@@ -516,7 +537,6 @@ struct gfs2_tune {
unsigned int gt_logd_secs; unsigned int gt_logd_secs;
unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */
unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */ unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */
unsigned int gt_quota_scale_num; /* Numerator */ unsigned int gt_quota_scale_num; /* Numerator */
unsigned int gt_quota_scale_den; /* Denominator */ unsigned int gt_quota_scale_den; /* Denominator */
...@@ -694,6 +714,7 @@ struct gfs2_sbd { ...@@ -694,6 +714,7 @@ struct gfs2_sbd {
struct list_head sd_quota_list; struct list_head sd_quota_list;
atomic_t sd_quota_count; atomic_t sd_quota_count;
struct mutex sd_quota_mutex; struct mutex sd_quota_mutex;
struct mutex sd_quota_sync_mutex;
wait_queue_head_t sd_quota_wait; wait_queue_head_t sd_quota_wait;
struct list_head sd_trunc_list; struct list_head sd_trunc_list;
spinlock_t sd_trunc_lock; spinlock_t sd_trunc_lock;
......
...@@ -379,6 +379,7 @@ static void munge_mode_uid_gid(const struct gfs2_inode *dip, ...@@ -379,6 +379,7 @@ static void munge_mode_uid_gid(const struct gfs2_inode *dip,
static int alloc_dinode(struct gfs2_inode *ip, u32 flags) static int alloc_dinode(struct gfs2_inode *ip, u32 flags)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc_parms ap = { .target = RES_DINODE, .aflags = flags, };
int error; int error;
int dblocks = 1; int dblocks = 1;
...@@ -386,7 +387,7 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags) ...@@ -386,7 +387,7 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags)
if (error) if (error)
goto out; goto out;
error = gfs2_inplace_reserve(ip, RES_DINODE, flags); error = gfs2_inplace_reserve(ip, &ap);
if (error) if (error)
goto out_quota; goto out_quota;
...@@ -472,6 +473,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -472,6 +473,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
struct gfs2_inode *ip, int arq) struct gfs2_inode *ip, int arq)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, };
int error; int error;
if (arq) { if (arq) {
...@@ -479,7 +481,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -479,7 +481,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
if (error) if (error)
goto fail_quota_locks; goto fail_quota_locks;
error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres, 0); error = gfs2_inplace_reserve(dip, &ap);
if (error) if (error)
goto fail_quota_locks; goto fail_quota_locks;
...@@ -584,17 +586,17 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -584,17 +586,17 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
d = d_splice_alias(inode, dentry); d = d_splice_alias(inode, dentry);
error = 0; error = 0;
if (file && !IS_ERR(d)) { if (file) {
if (d == NULL) if (S_ISREG(inode->i_mode)) {
d = dentry; WARN_ON(d != NULL);
if (S_ISREG(inode->i_mode)) error = finish_open(file, dentry, gfs2_open_common, opened);
error = finish_open(file, d, gfs2_open_common, opened); } else {
else
error = finish_no_open(file, d); error = finish_no_open(file, d);
}
} else {
dput(d);
} }
gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs);
if (IS_ERR(d))
return PTR_ERR(d);
return error; return error;
} else if (error != -ENOENT) { } else if (error != -ENOENT) {
goto fail_gunlock; goto fail_gunlock;
...@@ -713,7 +715,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -713,7 +715,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
fail_free_inode: fail_free_inode:
if (ip->i_gl) if (ip->i_gl)
gfs2_glock_put(ip->i_gl); gfs2_glock_put(ip->i_gl);
gfs2_rs_delete(ip); gfs2_rs_delete(ip, NULL);
free_inode_nonrcu(inode); free_inode_nonrcu(inode);
inode = NULL; inode = NULL;
fail_gunlock: fail_gunlock:
...@@ -781,8 +783,10 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry, ...@@ -781,8 +783,10 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
error = finish_open(file, dentry, gfs2_open_common, opened); error = finish_open(file, dentry, gfs2_open_common, opened);
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
if (error) if (error) {
dput(d);
return ERR_PTR(error); return ERR_PTR(error);
}
return d; return d;
} }
...@@ -874,11 +878,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -874,11 +878,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
error = 0; error = 0;
if (alloc_required) { if (alloc_required) {
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, };
error = gfs2_quota_lock_check(dip); error = gfs2_quota_lock_check(dip);
if (error) if (error)
goto out_gunlock; goto out_gunlock;
error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres, 0); error = gfs2_inplace_reserve(dip, &ap);
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
...@@ -1163,14 +1168,16 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1163,14 +1168,16 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
d = __gfs2_lookup(dir, dentry, file, opened); d = __gfs2_lookup(dir, dentry, file, opened);
if (IS_ERR(d)) if (IS_ERR(d))
return PTR_ERR(d); return PTR_ERR(d);
if (d == NULL) if (d != NULL)
d = dentry; dentry = d;
if (d->d_inode) { if (dentry->d_inode) {
if (!(*opened & FILE_OPENED)) if (!(*opened & FILE_OPENED))
return finish_no_open(file, d); return finish_no_open(file, dentry);
dput(d);
return 0; return 0;
} }
BUG_ON(d != NULL);
if (!(flags & O_CREAT)) if (!(flags & O_CREAT))
return -ENOENT; return -ENOENT;
...@@ -1385,11 +1392,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1385,11 +1392,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
goto out_gunlock; goto out_gunlock;
if (alloc_required) { if (alloc_required) {
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, };
error = gfs2_quota_lock_check(ndip); error = gfs2_quota_lock_check(ndip);
if (error) if (error)
goto out_gunlock; goto out_gunlock;
error = gfs2_inplace_reserve(ndip, sdp->sd_max_dirres, 0); error = gfs2_inplace_reserve(ndip, &ap);
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
......
...@@ -31,12 +31,6 @@ ...@@ -31,12 +31,6 @@
struct workqueue_struct *gfs2_control_wq; struct workqueue_struct *gfs2_control_wq;
static struct shrinker qd_shrinker = {
.count_objects = gfs2_qd_shrink_count,
.scan_objects = gfs2_qd_shrink_scan,
.seeks = DEFAULT_SEEKS,
};
static void gfs2_init_inode_once(void *foo) static void gfs2_init_inode_once(void *foo)
{ {
struct gfs2_inode *ip = foo; struct gfs2_inode *ip = foo;
...@@ -87,6 +81,10 @@ static int __init init_gfs2_fs(void) ...@@ -87,6 +81,10 @@ static int __init init_gfs2_fs(void)
if (error) if (error)
return error; return error;
error = list_lru_init(&gfs2_qd_lru);
if (error)
goto fail_lru;
error = gfs2_glock_init(); error = gfs2_glock_init();
if (error) if (error)
goto fail; goto fail;
...@@ -139,7 +137,7 @@ static int __init init_gfs2_fs(void) ...@@ -139,7 +137,7 @@ static int __init init_gfs2_fs(void)
if (!gfs2_rsrv_cachep) if (!gfs2_rsrv_cachep)
goto fail; goto fail;
register_shrinker(&qd_shrinker); register_shrinker(&gfs2_qd_shrinker);
error = register_filesystem(&gfs2_fs_type); error = register_filesystem(&gfs2_fs_type);
if (error) if (error)
...@@ -179,7 +177,9 @@ static int __init init_gfs2_fs(void) ...@@ -179,7 +177,9 @@ static int __init init_gfs2_fs(void)
fail_unregister: fail_unregister:
unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2_fs_type);
fail: fail:
unregister_shrinker(&qd_shrinker); list_lru_destroy(&gfs2_qd_lru);
fail_lru:
unregister_shrinker(&gfs2_qd_shrinker);
gfs2_glock_exit(); gfs2_glock_exit();
if (gfs2_rsrv_cachep) if (gfs2_rsrv_cachep)
...@@ -214,13 +214,14 @@ static int __init init_gfs2_fs(void) ...@@ -214,13 +214,14 @@ static int __init init_gfs2_fs(void)
static void __exit exit_gfs2_fs(void) static void __exit exit_gfs2_fs(void)
{ {
unregister_shrinker(&qd_shrinker); unregister_shrinker(&gfs2_qd_shrinker);
gfs2_glock_exit(); gfs2_glock_exit();
gfs2_unregister_debugfs(); gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type); unregister_filesystem(&gfs2meta_fs_type);
destroy_workqueue(gfs_recovery_wq); destroy_workqueue(gfs_recovery_wq);
destroy_workqueue(gfs2_control_wq); destroy_workqueue(gfs2_control_wq);
list_lru_destroy(&gfs2_qd_lru);
rcu_barrier(); rcu_barrier();
......
...@@ -51,7 +51,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt) ...@@ -51,7 +51,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
{ {
spin_lock_init(&gt->gt_spin); spin_lock_init(&gt->gt_spin);
gt->gt_quota_simul_sync = 64;
gt->gt_quota_warn_period = 10; gt->gt_quota_warn_period = 10;
gt->gt_quota_scale_num = 1; gt->gt_quota_scale_num = 1;
gt->gt_quota_scale_den = 1; gt->gt_quota_scale_den = 1;
...@@ -94,6 +93,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -94,6 +93,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
INIT_LIST_HEAD(&sdp->sd_quota_list); INIT_LIST_HEAD(&sdp->sd_quota_list);
mutex_init(&sdp->sd_quota_mutex); mutex_init(&sdp->sd_quota_mutex);
mutex_init(&sdp->sd_quota_sync_mutex);
init_waitqueue_head(&sdp->sd_quota_wait); init_waitqueue_head(&sdp->sd_quota_wait);
INIT_LIST_HEAD(&sdp->sd_trunc_list); INIT_LIST_HEAD(&sdp->sd_trunc_list);
spin_lock_init(&sdp->sd_trunc_lock); spin_lock_init(&sdp->sd_trunc_lock);
......
This diff is collapsed.
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
#ifndef __QUOTA_DOT_H__ #ifndef __QUOTA_DOT_H__
#define __QUOTA_DOT_H__ #define __QUOTA_DOT_H__
#include <linux/list_lru.h>
struct gfs2_inode; struct gfs2_inode;
struct gfs2_sbd; struct gfs2_sbd;
struct shrink_control;
#define NO_UID_QUOTA_CHANGE INVALID_UID #define NO_UID_QUOTA_CHANGE INVALID_UID
#define NO_GID_QUOTA_CHANGE INVALID_GID #define NO_GID_QUOTA_CHANGE INVALID_GID
...@@ -53,10 +54,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) ...@@ -53,10 +54,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
return ret; return ret;
} }
extern unsigned long gfs2_qd_shrink_count(struct shrinker *shrink,
struct shrink_control *sc);
extern unsigned long gfs2_qd_shrink_scan(struct shrinker *shrink,
struct shrink_control *sc);
extern const struct quotactl_ops gfs2_quotactl_ops; extern const struct quotactl_ops gfs2_quotactl_ops;
extern struct shrinker gfs2_qd_shrinker;
extern struct list_lru gfs2_qd_lru;
#endif /* __QUOTA_DOT_H__ */ #endif /* __QUOTA_DOT_H__ */
This diff is collapsed.
...@@ -40,7 +40,7 @@ extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh); ...@@ -40,7 +40,7 @@ extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
#define GFS2_AF_ORLOV 1 #define GFS2_AF_ORLOV 1
extern int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested, u32 flags); extern int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap);
extern void gfs2_inplace_release(struct gfs2_inode *ip); extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
...@@ -48,7 +48,7 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, ...@@ -48,7 +48,7 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
extern int gfs2_rs_alloc(struct gfs2_inode *ip); extern int gfs2_rs_alloc(struct gfs2_inode *ip);
extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs); extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
extern void gfs2_rs_delete(struct gfs2_inode *ip); extern void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount);
extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta); extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
......
...@@ -1526,7 +1526,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1526,7 +1526,7 @@ static void gfs2_evict_inode(struct inode *inode)
out: out:
/* Case 3 starts here */ /* Case 3 starts here */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
gfs2_rs_delete(ip); gfs2_rs_delete(ip, NULL);
gfs2_ordered_del_inode(ip); gfs2_ordered_del_inode(ip);
clear_inode(inode); clear_inode(inode);
gfs2_dir_hash_inval(ip); gfs2_dir_hash_inval(ip);
......
...@@ -587,7 +587,6 @@ TUNE_ATTR(max_readahead, 0); ...@@ -587,7 +587,6 @@ TUNE_ATTR(max_readahead, 0);
TUNE_ATTR(complain_secs, 0); TUNE_ATTR(complain_secs, 0);
TUNE_ATTR(statfs_slow, 0); TUNE_ATTR(statfs_slow, 0);
TUNE_ATTR(new_files_jdata, 0); TUNE_ATTR(new_files_jdata, 0);
TUNE_ATTR(quota_simul_sync, 1);
TUNE_ATTR(statfs_quantum, 1); TUNE_ATTR(statfs_quantum, 1);
TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store); TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
...@@ -597,7 +596,6 @@ static struct attribute *tune_attrs[] = { ...@@ -597,7 +596,6 @@ static struct attribute *tune_attrs[] = {
&tune_attr_max_readahead.attr, &tune_attr_max_readahead.attr,
&tune_attr_complain_secs.attr, &tune_attr_complain_secs.attr,
&tune_attr_statfs_slow.attr, &tune_attr_statfs_slow.attr,
&tune_attr_quota_simul_sync.attr,
&tune_attr_statfs_quantum.attr, &tune_attr_statfs_quantum.attr,
&tune_attr_quota_scale.attr, &tune_attr_quota_scale.attr,
&tune_attr_new_files_jdata.attr, &tune_attr_new_files_jdata.attr,
......
...@@ -268,23 +268,3 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, ...@@ -268,23 +268,3 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
return rv; return rv;
} }
void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
unsigned int bit, int new_value)
{
unsigned int c, o, b = bit;
int old_value;
c = b / (8 * PAGE_SIZE);
b %= 8 * PAGE_SIZE;
o = b / 8;
b %= 8;
old_value = (bitmap[c][o] & (1 << b));
gfs2_assert_withdraw(sdp, !old_value != !new_value);
if (new_value)
bitmap[c][o] |= 1 << b;
else
bitmap[c][o] &= ~(1 << b);
}
...@@ -164,8 +164,6 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, ...@@ -164,8 +164,6 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
#define gfs2_tune_get(sdp, field) \ #define gfs2_tune_get(sdp, field) \
gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
unsigned int bit, int new_value);
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...); int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...);
#endif /* __UTIL_DOT_H__ */ #endif /* __UTIL_DOT_H__ */
......
...@@ -723,6 +723,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -723,6 +723,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
unsigned int blks, unsigned int blks,
ea_skeleton_call_t skeleton_call, void *private) ea_skeleton_call_t skeleton_call, void *private)
{ {
struct gfs2_alloc_parms ap = { .target = blks };
struct buffer_head *dibh; struct buffer_head *dibh;
int error; int error;
...@@ -734,7 +735,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -734,7 +735,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
if (error) if (error)
return error; return error;
error = gfs2_inplace_reserve(ip, blks, 0); error = gfs2_inplace_reserve(ip, &ap);
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
......
...@@ -36,4 +36,10 @@ extern int lockref_put_or_lock(struct lockref *); ...@@ -36,4 +36,10 @@ extern int lockref_put_or_lock(struct lockref *);
extern void lockref_mark_dead(struct lockref *); extern void lockref_mark_dead(struct lockref *);
extern int lockref_get_not_dead(struct lockref *); extern int lockref_get_not_dead(struct lockref *);
/* Must be called under spinlock for reliable results */
static inline int __lockref_is_dead(const struct lockref *l)
{
return ((int)l->count < 0);
}
#endif /* __LINUX_LOCKREF_H */ #endif /* __LINUX_LOCKREF_H */
...@@ -153,6 +153,7 @@ void lockref_mark_dead(struct lockref *lockref) ...@@ -153,6 +153,7 @@ void lockref_mark_dead(struct lockref *lockref)
assert_spin_locked(&lockref->lock); assert_spin_locked(&lockref->lock);
lockref->count = -128; lockref->count = -128;
} }
EXPORT_SYMBOL(lockref_mark_dead);
/** /**
* lockref_get_not_dead - Increments count unless the ref is dead * lockref_get_not_dead - Increments count unless the ref is dead
......
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