xref: /openbmc/linux/fs/reiserfs/lock.c (revision b2441318)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2f466c6fdSAl Viro #include "reiserfs.h"
38ebc4232SFrederic Weisbecker #include <linux/mutex.h>
48ebc4232SFrederic Weisbecker 
58ebc4232SFrederic Weisbecker /*
68ebc4232SFrederic Weisbecker  * The previous reiserfs locking scheme was heavily based on
78ebc4232SFrederic Weisbecker  * the tricky properties of the Bkl:
88ebc4232SFrederic Weisbecker  *
98ebc4232SFrederic Weisbecker  * - it was acquired recursively by a same task
108ebc4232SFrederic Weisbecker  * - the performances relied on the release-while-schedule() property
118ebc4232SFrederic Weisbecker  *
128ebc4232SFrederic Weisbecker  * Now that we replace it by a mutex, we still want to keep the same
138ebc4232SFrederic Weisbecker  * recursive property to avoid big changes in the code structure.
148ebc4232SFrederic Weisbecker  * We use our own lock_owner here because the owner field on a mutex
158ebc4232SFrederic Weisbecker  * is only available in SMP or mutex debugging, also we only need this field
168ebc4232SFrederic Weisbecker  * for this mutex, no need for a system wide mutex facility.
178ebc4232SFrederic Weisbecker  *
188ebc4232SFrederic Weisbecker  * Also this lock is often released before a call that could block because
1925985edcSLucas De Marchi  * reiserfs performances were partially based on the release while schedule()
208ebc4232SFrederic Weisbecker  * property of the Bkl.
218ebc4232SFrederic Weisbecker  */
reiserfs_write_lock(struct super_block * s)228ebc4232SFrederic Weisbecker void reiserfs_write_lock(struct super_block *s)
238ebc4232SFrederic Weisbecker {
248ebc4232SFrederic Weisbecker 	struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
258ebc4232SFrederic Weisbecker 
268ebc4232SFrederic Weisbecker 	if (sb_i->lock_owner != current) {
278ebc4232SFrederic Weisbecker 		mutex_lock(&sb_i->lock);
288ebc4232SFrederic Weisbecker 		sb_i->lock_owner = current;
298ebc4232SFrederic Weisbecker 	}
308ebc4232SFrederic Weisbecker 
318ebc4232SFrederic Weisbecker 	/* No need to protect it, only the current task touches it */
328ebc4232SFrederic Weisbecker 	sb_i->lock_depth++;
338ebc4232SFrederic Weisbecker }
348ebc4232SFrederic Weisbecker 
reiserfs_write_unlock(struct super_block * s)358ebc4232SFrederic Weisbecker void reiserfs_write_unlock(struct super_block *s)
368ebc4232SFrederic Weisbecker {
378ebc4232SFrederic Weisbecker 	struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
388ebc4232SFrederic Weisbecker 
398ebc4232SFrederic Weisbecker 	/*
408ebc4232SFrederic Weisbecker 	 * Are we unlocking without even holding the lock?
4180503185SFrederic Weisbecker 	 * Such a situation must raise a BUG() if we don't want
4280503185SFrederic Weisbecker 	 * to corrupt the data.
438ebc4232SFrederic Weisbecker 	 */
4480503185SFrederic Weisbecker 	BUG_ON(sb_i->lock_owner != current);
458ebc4232SFrederic Weisbecker 
468ebc4232SFrederic Weisbecker 	if (--sb_i->lock_depth == -1) {
478ebc4232SFrederic Weisbecker 		sb_i->lock_owner = NULL;
488ebc4232SFrederic Weisbecker 		mutex_unlock(&sb_i->lock);
498ebc4232SFrederic Weisbecker 	}
508ebc4232SFrederic Weisbecker }
518ebc4232SFrederic Weisbecker 
reiserfs_write_unlock_nested(struct super_block * s)52278f6679SJeff Mahoney int __must_check reiserfs_write_unlock_nested(struct super_block *s)
53278f6679SJeff Mahoney {
54278f6679SJeff Mahoney 	struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
55278f6679SJeff Mahoney 	int depth;
56278f6679SJeff Mahoney 
57278f6679SJeff Mahoney 	/* this can happen when the lock isn't always held */
58278f6679SJeff Mahoney 	if (sb_i->lock_owner != current)
59278f6679SJeff Mahoney 		return -1;
60278f6679SJeff Mahoney 
61278f6679SJeff Mahoney 	depth = sb_i->lock_depth;
62278f6679SJeff Mahoney 
63278f6679SJeff Mahoney 	sb_i->lock_depth = -1;
64278f6679SJeff Mahoney 	sb_i->lock_owner = NULL;
65278f6679SJeff Mahoney 	mutex_unlock(&sb_i->lock);
66278f6679SJeff Mahoney 
67278f6679SJeff Mahoney 	return depth;
68278f6679SJeff Mahoney }
69278f6679SJeff Mahoney 
reiserfs_write_lock_nested(struct super_block * s,int depth)70278f6679SJeff Mahoney void reiserfs_write_lock_nested(struct super_block *s, int depth)
71daf88c89SFrederic Weisbecker {
72daf88c89SFrederic Weisbecker 	struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
73daf88c89SFrederic Weisbecker 
74278f6679SJeff Mahoney 	/* this can happen when the lock isn't always held */
75278f6679SJeff Mahoney 	if (depth == -1)
76278f6679SJeff Mahoney 		return;
77278f6679SJeff Mahoney 
78daf88c89SFrederic Weisbecker 	mutex_lock(&sb_i->lock);
79daf88c89SFrederic Weisbecker 	sb_i->lock_owner = current;
80278f6679SJeff Mahoney 	sb_i->lock_depth = depth;
81daf88c89SFrederic Weisbecker }
82daf88c89SFrederic Weisbecker 
83daf88c89SFrederic Weisbecker /*
848ebc4232SFrederic Weisbecker  * Utility function to force a BUG if it is called without the superblock
858ebc4232SFrederic Weisbecker  * write lock held.  caller is the string printed just before calling BUG()
868ebc4232SFrederic Weisbecker  */
reiserfs_check_lock_depth(struct super_block * sb,char * caller)878ebc4232SFrederic Weisbecker void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
888ebc4232SFrederic Weisbecker {
898ebc4232SFrederic Weisbecker 	struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);
908ebc4232SFrederic Weisbecker 
91278f6679SJeff Mahoney 	WARN_ON(sb_i->lock_depth < 0);
928ebc4232SFrederic Weisbecker }
93c4a62ca3SFrederic Weisbecker 
94c4a62ca3SFrederic Weisbecker #ifdef CONFIG_REISERFS_CHECK
reiserfs_lock_check_recursive(struct super_block * sb)95c4a62ca3SFrederic Weisbecker void reiserfs_lock_check_recursive(struct super_block *sb)
96c4a62ca3SFrederic Weisbecker {
97c4a62ca3SFrederic Weisbecker 	struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);
98c4a62ca3SFrederic Weisbecker 
99c4a62ca3SFrederic Weisbecker 	WARN_ONCE((sb_i->lock_depth > 0), "Unwanted recursive reiserfs lock!\n");
100c4a62ca3SFrederic Weisbecker }
101c4a62ca3SFrederic Weisbecker #endif
102