Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
df38988c
Commit
df38988c
authored
Feb 02, 2003
by
Andrew Morton
Committed by
Linus Torvalds
Feb 02, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] quota semaphore fix
The second quota locking fix. Sorry, I seem to have misplaced the changelog.
parent
9a747377
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
60 additions
and
47 deletions
+60
-47
fs/dquot.c
fs/dquot.c
+47
-42
fs/ext2/inode.c
fs/ext2/inode.c
+6
-0
fs/quota.c
fs/quota.c
+3
-3
fs/super.c
fs/super.c
+2
-1
include/linux/quota.h
include/linux/quota.h
+2
-1
No files found.
fs/dquot.c
View file @
df38988c
...
...
@@ -159,7 +159,7 @@ static void put_quota_format(struct quota_format_type *fmt)
* Note that any operation which operates on dquot data (ie. dq_dqb) must
* hold dq_data_lock.
*
* Any operation working with dquots must hold dq
off
_sem. If operation is
* Any operation working with dquots must hold dq
ptr
_sem. If operation is
* just reading pointers from inodes than read lock is enough. If pointers
* are altered function must hold write lock.
*
...
...
@@ -270,7 +270,7 @@ static int commit_dqblk(struct dquot *dquot)
}
/* Invalidate all dquots on the list. Note that this function is called after
* quota is disabled so no new quota might be created. Because we hold dq
off
_sem
* quota is disabled so no new quota might be created. Because we hold dq
ptr
_sem
* for writing and pointers were already removed from inodes we actually know that
* no quota for this sb+type should be held. */
static
void
invalidate_dquots
(
struct
super_block
*
sb
,
int
type
)
...
...
@@ -287,7 +287,7 @@ static void invalidate_dquots(struct super_block *sb, int type)
if
(
dquot
->
dq_type
!=
type
)
continue
;
#ifdef __DQUOT_PARANOIA
/* There should be no users of quota - we hold dq
off
_sem for writing */
/* There should be no users of quota - we hold dq
ptr
_sem for writing */
if
(
atomic_read
(
&
dquot
->
dq_count
))
BUG
();
#endif
...
...
@@ -307,7 +307,7 @@ static int vfs_quota_sync(struct super_block *sb, int type)
struct
quota_info
*
dqopt
=
sb_dqopt
(
sb
);
int
cnt
;
down_read
(
&
dqopt
->
dq
off
_sem
);
down_read
(
&
dqopt
->
dq
ptr
_sem
);
restart:
/* At this point any dirty dquot will definitely be written so we can clear
dirty flag from info */
...
...
@@ -340,7 +340,7 @@ static int vfs_quota_sync(struct super_block *sb, int type)
spin_lock
(
&
dq_list_lock
);
dqstats
.
syncs
++
;
spin_unlock
(
&
dq_list_lock
);
up_read
(
&
dqopt
->
dq
off
_sem
);
up_read
(
&
dqopt
->
dq
ptr
_sem
);
return
0
;
}
...
...
@@ -427,7 +427,7 @@ static int shrink_dqcache_memory(int nr, unsigned int gfp_mask)
/*
* Put reference to dquot
* NOTE: If you change this function please check whether dqput_blocks() works right...
* MUST be called with dq
off
_sem held
* MUST be called with dq
ptr
_sem held
*/
static
void
dqput
(
struct
dquot
*
dquot
)
{
...
...
@@ -492,7 +492,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
/*
* Get reference to dquot
* MUST be called with dq
off
_sem held
* MUST be called with dq
ptr
_sem held
*/
static
struct
dquot
*
dqget
(
struct
super_block
*
sb
,
unsigned
int
id
,
int
type
)
{
...
...
@@ -553,7 +553,7 @@ static int dqinit_needed(struct inode *inode, int type)
return
0
;
}
/* This routine is guarded by dq
off
_sem semaphore */
/* This routine is guarded by dq
ptr
_sem semaphore */
static
void
add_dquot_ref
(
struct
super_block
*
sb
,
int
type
)
{
struct
list_head
*
p
;
...
...
@@ -586,7 +586,7 @@ static inline int dqput_blocks(struct dquot *dquot)
}
/* Remove references to dquots from inode - add dquot to list for freeing if needed */
/* We can't race with anybody because we hold dq
off
_sem for writing... */
/* We can't race with anybody because we hold dq
ptr
_sem for writing... */
int
remove_inode_dquot_ref
(
struct
inode
*
inode
,
int
type
,
struct
list_head
*
tofree_head
)
{
struct
dquot
*
dquot
=
inode
->
i_dquot
[
type
];
...
...
@@ -829,10 +829,10 @@ void dquot_initialize(struct inode *inode, int type)
unsigned
int
id
=
0
;
int
cnt
;
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
/* Having dq
off lock
we know NOQUOTA flags can't be altered... */
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
/* Having dq
ptr_sem
we know NOQUOTA flags can't be altered... */
if
(
IS_NOQUOTA
(
inode
))
{
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
return
;
}
/* Build list of quotas to initialize... */
...
...
@@ -853,7 +853,7 @@ void dquot_initialize(struct inode *inode, int type)
inode
->
i_flags
|=
S_QUOTA
;
}
}
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
}
/*
...
...
@@ -876,9 +876,9 @@ static void dquot_drop_nolock(struct inode *inode)
void
dquot_drop
(
struct
inode
*
inode
)
{
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
dquot_drop_nolock
(
inode
);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
}
/*
...
...
@@ -892,7 +892,7 @@ int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
warntype
[
cnt
]
=
NOWARN
;
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
spin_lock
(
&
dq_data_lock
);
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
{
if
(
inode
->
i_dquot
[
cnt
]
==
NODQUOT
)
...
...
@@ -910,7 +910,7 @@ int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
warn_put_all:
spin_unlock
(
&
dq_data_lock
);
flush_warnings
(
inode
->
i_dquot
,
warntype
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
return
ret
;
}
...
...
@@ -924,7 +924,7 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number)
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
warntype
[
cnt
]
=
NOWARN
;
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
spin_lock
(
&
dq_data_lock
);
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
{
if
(
inode
->
i_dquot
[
cnt
]
==
NODQUOT
)
...
...
@@ -942,7 +942,7 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number)
warn_put_all:
spin_unlock
(
&
dq_data_lock
);
flush_warnings
((
struct
dquot
**
)
inode
->
i_dquot
,
warntype
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
return
ret
;
}
...
...
@@ -953,7 +953,7 @@ void dquot_free_space(struct inode *inode, qsize_t number)
{
unsigned
int
cnt
;
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
spin_lock
(
&
dq_data_lock
);
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
{
if
(
inode
->
i_dquot
[
cnt
]
==
NODQUOT
)
...
...
@@ -962,7 +962,7 @@ void dquot_free_space(struct inode *inode, qsize_t number)
}
inode_sub_bytes
(
inode
,
number
);
spin_unlock
(
&
dq_data_lock
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
}
/*
...
...
@@ -972,7 +972,7 @@ void dquot_free_inode(const struct inode *inode, unsigned long number)
{
unsigned
int
cnt
;
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
spin_lock
(
&
dq_data_lock
);
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
{
if
(
inode
->
i_dquot
[
cnt
]
==
NODQUOT
)
...
...
@@ -980,7 +980,7 @@ void dquot_free_inode(const struct inode *inode, unsigned long number)
dquot_decr_inodes
(
inode
->
i_dquot
[
cnt
],
number
);
}
spin_unlock
(
&
dq_data_lock
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
}
/*
...
...
@@ -1002,7 +1002,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
transfer_to
[
cnt
]
=
transfer_from
[
cnt
]
=
NODQUOT
;
warntype
[
cnt
]
=
NOWARN
;
}
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
down_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
if
(
IS_NOQUOTA
(
inode
))
/* File without quota accounting? */
goto
warn_put_all
;
/* First build the transfer_to list - here we can block on reading of dquots... */
...
...
@@ -1058,7 +1058,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
if
(
transfer_from
[
cnt
]
!=
NODQUOT
)
dqput
(
transfer_from
[
cnt
]);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
off
_sem
);
up_write
(
&
sb_dqopt
(
inode
->
i_sb
)
->
dq
ptr
_sem
);
return
ret
;
}
...
...
@@ -1114,7 +1114,8 @@ int vfs_quota_off(struct super_block *sb, int type)
goto
out
;
/* We need to serialize quota_off() for device */
down_write
(
&
dqopt
->
dqoff_sem
);
down
(
&
dqopt
->
dqonoff_sem
);
down_write
(
&
dqopt
->
dqptr_sem
);
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
{
if
(
type
!=
-
1
&&
cnt
!=
type
)
continue
;
...
...
@@ -1145,7 +1146,8 @@ int vfs_quota_off(struct super_block *sb, int type)
dqopt
->
info
[
cnt
].
dqi_bgrace
=
0
;
dqopt
->
ops
[
cnt
]
=
NULL
;
}
up_write
(
&
dqopt
->
dqoff_sem
);
up_write
(
&
dqopt
->
dqptr_sem
);
up
(
&
dqopt
->
dqonoff_sem
);
out:
return
0
;
}
...
...
@@ -1177,7 +1179,8 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
if
(
!
S_ISREG
(
inode
->
i_mode
))
goto
out_f
;
down_write
(
&
dqopt
->
dqoff_sem
);
down
(
&
dqopt
->
dqonoff_sem
);
down_write
(
&
dqopt
->
dqptr_sem
);
if
(
sb_has_quota_enabled
(
sb
,
type
))
{
error
=
-
EBUSY
;
goto
out_lock
;
...
...
@@ -1200,17 +1203,19 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
}
up
(
&
dqopt
->
dqio_sem
);
set_enable_flags
(
dqopt
,
type
);
up_write
(
&
dqopt
->
dqptr_sem
);
add_dquot_ref
(
sb
,
type
);
up
(
&
dqopt
->
dqonoff_sem
);
up_write
(
&
dqopt
->
dqoff_sem
);
return
0
;
out_file_init:
inode
->
i_flags
=
oldflags
;
dqopt
->
files
[
type
]
=
NULL
;
out_lock:
up_write
(
&
dqopt
->
dqoff_sem
);
up_write
(
&
dqopt
->
dqptr_sem
);
up
(
&
dqopt
->
dqonoff_sem
);
out_f:
filp_close
(
f
,
NULL
);
out_fmt:
...
...
@@ -1241,14 +1246,14 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
{
struct
dquot
*
dquot
;
down_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
!
(
dquot
=
dqget
(
sb
,
id
,
type
)))
{
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
-
ESRCH
;
}
do_get_dqblk
(
dquot
,
di
);
dqput
(
dquot
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
0
;
}
...
...
@@ -1310,14 +1315,14 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
{
struct
dquot
*
dquot
;
down_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
!
(
dquot
=
dqget
(
sb
,
id
,
type
)))
{
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
-
ESRCH
;
}
do_set_dqblk
(
dquot
,
di
);
dqput
(
dquot
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
0
;
}
...
...
@@ -1326,9 +1331,9 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
{
struct
mem_dqinfo
*
mi
;
down_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
!
sb_has_quota_enabled
(
sb
,
type
))
{
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
-
ESRCH
;
}
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
...
...
@@ -1338,7 +1343,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
ii
->
dqi_flags
=
mi
->
dqi_flags
&
DQF_MASK
;
ii
->
dqi_valid
=
IIF_ALL
;
spin_unlock
(
&
dq_data_lock
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
0
;
}
...
...
@@ -1347,9 +1352,9 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
{
struct
mem_dqinfo
*
mi
;
down_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
!
sb_has_quota_enabled
(
sb
,
type
))
{
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
-
ESRCH
;
}
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
...
...
@@ -1362,7 +1367,7 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
mi
->
dqi_flags
=
(
mi
->
dqi_flags
&
~
DQF_MASK
)
|
(
ii
->
dqi_flags
&
DQF_MASK
);
mark_info_dirty
(
mi
);
spin_unlock
(
&
dq_data_lock
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
0
;
}
...
...
fs/ext2/inode.c
View file @
df38988c
...
...
@@ -1239,6 +1239,12 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
error
=
inode_change_ok
(
inode
,
iattr
);
if
(
error
)
return
error
;
if
((
iattr
->
ia_valid
&
ATTR_UID
&&
iattr
->
ia_uid
!=
inode
->
i_uid
)
||
(
iattr
->
ia_valid
&
ATTR_GID
&&
iattr
->
ia_gid
!=
inode
->
i_gid
))
{
error
=
DQUOT_TRANSFER
(
inode
,
iattr
)
?
-
EDQUOT
:
0
;
if
(
error
)
return
error
;
}
inode_setattr
(
inode
,
iattr
);
if
(
iattr
->
ia_valid
&
ATTR_MODE
)
error
=
ext2_acl_chmod
(
inode
);
...
...
fs/quota.c
View file @
df38988c
...
...
@@ -123,13 +123,13 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, cadd
case
Q_GETFMT
:
{
__u32
fmt
;
down_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
down_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
!
sb_has_quota_enabled
(
sb
,
type
))
{
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
return
-
ESRCH
;
}
fmt
=
sb_dqopt
(
sb
)
->
info
[
type
].
dqi_format
->
qf_fmt_id
;
up_read
(
&
sb_dqopt
(
sb
)
->
dq
off
_sem
);
up_read
(
&
sb_dqopt
(
sb
)
->
dq
ptr
_sem
);
if
(
copy_to_user
(
addr
,
&
fmt
,
sizeof
(
fmt
)))
return
-
EFAULT
;
return
0
;
...
...
fs/super.c
View file @
df38988c
...
...
@@ -71,7 +71,8 @@ static struct super_block *alloc_super(void)
atomic_set
(
&
s
->
s_active
,
1
);
sema_init
(
&
s
->
s_vfs_rename_sem
,
1
);
sema_init
(
&
s
->
s_dquot
.
dqio_sem
,
1
);
init_rwsem
(
&
s
->
s_dquot
.
dqoff_sem
);
sema_init
(
&
s
->
s_dquot
.
dqonoff_sem
,
1
);
init_rwsem
(
&
s
->
s_dquot
.
dqptr_sem
);
s
->
s_maxbytes
=
MAX_NON_LFS
;
s
->
dq_op
=
sb_dquot_ops
;
s
->
s_qcop
=
sb_quotactl_ops
;
...
...
include/linux/quota.h
View file @
df38988c
...
...
@@ -280,7 +280,8 @@ struct quota_format_type {
struct
quota_info
{
unsigned
int
flags
;
/* Flags for diskquotas on this device */
struct
semaphore
dqio_sem
;
/* lock device while I/O in progress */
struct
rw_semaphore
dqoff_sem
;
/* serialize quota_off() and quota_on() on device and ops using quota_info struct, pointers from inode to dquots */
struct
semaphore
dqonoff_sem
;
/* Serialize quotaon & quotaoff */
struct
rw_semaphore
dqptr_sem
;
/* serialize ops using quota_info struct, pointers from inode to dquots */
struct
file
*
files
[
MAXQUOTAS
];
/* fp's to quotafiles */
struct
mem_dqinfo
info
[
MAXQUOTAS
];
/* Information for each quota type */
struct
quota_format_ops
*
ops
[
MAXQUOTAS
];
/* Operations for each type */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment