18ebc4232SFrederic Weisbecker #include <linux/reiserfs_fs.h> 28ebc4232SFrederic Weisbecker #include <linux/mutex.h> 38ebc4232SFrederic Weisbecker 48ebc4232SFrederic Weisbecker /* 58ebc4232SFrederic Weisbecker * The previous reiserfs locking scheme was heavily based on 68ebc4232SFrederic Weisbecker * the tricky properties of the Bkl: 78ebc4232SFrederic Weisbecker * 88ebc4232SFrederic Weisbecker * - it was acquired recursively by a same task 98ebc4232SFrederic Weisbecker * - the performances relied on the release-while-schedule() property 108ebc4232SFrederic Weisbecker * 118ebc4232SFrederic Weisbecker * Now that we replace it by a mutex, we still want to keep the same 128ebc4232SFrederic Weisbecker * recursive property to avoid big changes in the code structure. 138ebc4232SFrederic Weisbecker * We use our own lock_owner here because the owner field on a mutex 148ebc4232SFrederic Weisbecker * is only available in SMP or mutex debugging, also we only need this field 158ebc4232SFrederic Weisbecker * for this mutex, no need for a system wide mutex facility. 168ebc4232SFrederic Weisbecker * 178ebc4232SFrederic Weisbecker * Also this lock is often released before a call that could block because 1825985edcSLucas De Marchi * reiserfs performances were partially based on the release while schedule() 198ebc4232SFrederic Weisbecker * property of the Bkl. 208ebc4232SFrederic Weisbecker */ 218ebc4232SFrederic Weisbecker void reiserfs_write_lock(struct super_block *s) 228ebc4232SFrederic Weisbecker { 238ebc4232SFrederic Weisbecker struct reiserfs_sb_info *sb_i = REISERFS_SB(s); 248ebc4232SFrederic Weisbecker 258ebc4232SFrederic Weisbecker if (sb_i->lock_owner != current) { 268ebc4232SFrederic Weisbecker mutex_lock(&sb_i->lock); 278ebc4232SFrederic Weisbecker sb_i->lock_owner = current; 288ebc4232SFrederic Weisbecker } 298ebc4232SFrederic Weisbecker 308ebc4232SFrederic Weisbecker /* No need to protect it, only the current task touches it */ 318ebc4232SFrederic Weisbecker sb_i->lock_depth++; 328ebc4232SFrederic Weisbecker } 338ebc4232SFrederic Weisbecker 348ebc4232SFrederic Weisbecker void reiserfs_write_unlock(struct super_block *s) 358ebc4232SFrederic Weisbecker { 368ebc4232SFrederic Weisbecker struct reiserfs_sb_info *sb_i = REISERFS_SB(s); 378ebc4232SFrederic Weisbecker 388ebc4232SFrederic Weisbecker /* 398ebc4232SFrederic Weisbecker * Are we unlocking without even holding the lock? 4080503185SFrederic Weisbecker * Such a situation must raise a BUG() if we don't want 4180503185SFrederic Weisbecker * to corrupt the data. 428ebc4232SFrederic Weisbecker */ 4380503185SFrederic Weisbecker BUG_ON(sb_i->lock_owner != current); 448ebc4232SFrederic Weisbecker 458ebc4232SFrederic Weisbecker if (--sb_i->lock_depth == -1) { 468ebc4232SFrederic Weisbecker sb_i->lock_owner = NULL; 478ebc4232SFrederic Weisbecker mutex_unlock(&sb_i->lock); 488ebc4232SFrederic Weisbecker } 498ebc4232SFrederic Weisbecker } 508ebc4232SFrederic Weisbecker 518ebc4232SFrederic Weisbecker /* 52daf88c89SFrederic Weisbecker * If we already own the lock, just exit and don't increase the depth. 53daf88c89SFrederic Weisbecker * Useful when we don't want to lock more than once. 54daf88c89SFrederic Weisbecker * 55daf88c89SFrederic Weisbecker * We always return the lock_depth we had before calling 56daf88c89SFrederic Weisbecker * this function. 57daf88c89SFrederic Weisbecker */ 58daf88c89SFrederic Weisbecker int reiserfs_write_lock_once(struct super_block *s) 59daf88c89SFrederic Weisbecker { 60daf88c89SFrederic Weisbecker struct reiserfs_sb_info *sb_i = REISERFS_SB(s); 61daf88c89SFrederic Weisbecker 62daf88c89SFrederic Weisbecker if (sb_i->lock_owner != current) { 63daf88c89SFrederic Weisbecker mutex_lock(&sb_i->lock); 64daf88c89SFrederic Weisbecker sb_i->lock_owner = current; 65daf88c89SFrederic Weisbecker return sb_i->lock_depth++; 66daf88c89SFrederic Weisbecker } 67daf88c89SFrederic Weisbecker 68daf88c89SFrederic Weisbecker return sb_i->lock_depth; 69daf88c89SFrederic Weisbecker } 70daf88c89SFrederic Weisbecker 71daf88c89SFrederic Weisbecker void reiserfs_write_unlock_once(struct super_block *s, int lock_depth) 72daf88c89SFrederic Weisbecker { 73daf88c89SFrederic Weisbecker if (lock_depth == -1) 74daf88c89SFrederic Weisbecker reiserfs_write_unlock(s); 75daf88c89SFrederic Weisbecker } 76daf88c89SFrederic Weisbecker 77daf88c89SFrederic Weisbecker /* 788ebc4232SFrederic Weisbecker * Utility function to force a BUG if it is called without the superblock 798ebc4232SFrederic Weisbecker * write lock held. caller is the string printed just before calling BUG() 808ebc4232SFrederic Weisbecker */ 818ebc4232SFrederic Weisbecker void reiserfs_check_lock_depth(struct super_block *sb, char *caller) 828ebc4232SFrederic Weisbecker { 838ebc4232SFrederic Weisbecker struct reiserfs_sb_info *sb_i = REISERFS_SB(sb); 848ebc4232SFrederic Weisbecker 858ebc4232SFrederic Weisbecker if (sb_i->lock_depth < 0) 868ebc4232SFrederic Weisbecker reiserfs_panic(sb, "%s called without kernel lock held %d", 878ebc4232SFrederic Weisbecker caller); 888ebc4232SFrederic Weisbecker } 89c4a62ca3SFrederic Weisbecker 90c4a62ca3SFrederic Weisbecker #ifdef CONFIG_REISERFS_CHECK 91c4a62ca3SFrederic Weisbecker void reiserfs_lock_check_recursive(struct super_block *sb) 92c4a62ca3SFrederic Weisbecker { 93c4a62ca3SFrederic Weisbecker struct reiserfs_sb_info *sb_i = REISERFS_SB(sb); 94c4a62ca3SFrederic Weisbecker 95c4a62ca3SFrederic Weisbecker WARN_ONCE((sb_i->lock_depth > 0), "Unwanted recursive reiserfs lock!\n"); 96c4a62ca3SFrederic Weisbecker } 97c4a62ca3SFrederic Weisbecker #endif 98