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
704a6dfc
Commit
704a6dfc
authored
May 28, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge quota update
parents
155aba2e
6a0e8d78
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
78 additions
and
819 deletions
+78
-819
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/ia32_entry.S
+1
-1
arch/ia64/ia32/sys_ia32.c
arch/ia64/ia32/sys_ia32.c
+0
-91
arch/s390x/kernel/linux32.c
arch/s390x/kernel/linux32.c
+0
-91
arch/s390x/kernel/wrapper32.S
arch/s390x/kernel/wrapper32.S
+1
-1
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sparc32.c
+0
-91
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/systbls.S
+1
-1
fs/Config.help
fs/Config.help
+0
-15
fs/Config.in
fs/Config.in
+2
-5
fs/Makefile
fs/Makefile
+2
-1
fs/dquot.c
fs/dquot.c
+39
-23
fs/quota.c
fs/quota.c
+1
-394
fs/quota_v1.c
fs/quota_v1.c
+4
-2
fs/quota_v2.c
fs/quota_v2.c
+4
-2
include/linux/quota.h
include/linux/quota.h
+10
-14
include/linux/quotacompat.h
include/linux/quotacompat.h
+0
-86
include/linux/sysctl.h
include/linux/sysctl.h
+13
-1
No files found.
arch/ia64/ia32/ia32_entry.S
View file @
704a6dfc
...
@@ -322,7 +322,7 @@ ia32_syscall_table:
...
@@ -322,7 +322,7 @@ ia32_syscall_table:
data8
sys32_ni_syscall
/*
init_module
*/
data8
sys32_ni_syscall
/*
init_module
*/
data8
sys32_ni_syscall
/*
delete_module
*/
data8
sys32_ni_syscall
/*
delete_module
*/
data8
sys32_ni_syscall
/*
get_kernel_syms
*/
/*
130
*/
data8
sys32_ni_syscall
/*
get_kernel_syms
*/
/*
130
*/
data8
sys
32
_quotactl
data8
sys_quotactl
data8
sys_getpgid
data8
sys_getpgid
data8
sys_fchdir
data8
sys_fchdir
data8
sys32_ni_syscall
/*
sys_bdflush
*/
data8
sys32_ni_syscall
/*
sys_bdflush
*/
...
...
arch/ia64/ia32/sys_ia32.c
View file @
704a6dfc
...
@@ -3669,97 +3669,6 @@ getname32 (const char *filename)
...
@@ -3669,97 +3669,6 @@ getname32 (const char *filename)
return
result
;
return
result
;
}
}
extern
asmlinkage
long
sys_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
);
#ifdef CONFIG_QIFACE_COMPAT
#ifdef CONFIG_QIFACE_V1
struct
user_dqblk32
{
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u32
dqb_curblocks
;
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v1c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
#define Q_COMP_SETQLIM Q_V1_SETQLIM
#define Q_COMP_SETUSE Q_V1_SETUSE
#else
struct
user_dqblk32
{
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u64
dqb_curspace
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v2c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
#define Q_COMP_SETQLIM Q_V2_SETQLIM
#define Q_COMP_SETUSE Q_V2_SETUSE
#endif
asmlinkage
long
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
int
cmds
=
cmd
>>
SUBCMDSHIFT
;
long
err
;
comp_dqblk_t
d
;
mm_segment_t
old_fs
;
char
*
spec
;
switch
(
cmds
)
{
case
Q_COMP_GETQUOTA
:
break
;
case
Q_COMP_SETQUOTA
:
case
Q_COMP_SETUSE
:
case
Q_COMP_SETQLIM
:
if
(
copy_from_user
(
&
d
,
(
struct
user_dqblk32
*
)
addr
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
d
.
dqb_itime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
;
d
.
dqb_btime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
;
break
;
default:
return
sys_quotactl
(
cmd
,
special
,
id
,
(
__kernel_caddr_t
)
addr
);
}
spec
=
getname
(
special
);
err
=
PTR_ERR
(
spec
);
if
(
IS_ERR
(
spec
))
return
err
;
old_fs
=
get_fs
();
set_fs
(
KERNEL_DS
);
err
=
sys_quotactl
(
cmd
,
(
const
char
*
)
spec
,
id
,
(
__kernel_caddr_t
)
&
d
);
set_fs
(
old_fs
);
putname
(
spec
);
if
(
err
)
return
err
;
if
(
cmds
==
Q_COMP_GETQUOTA
)
{
__kernel_time_t
b
=
d
.
dqb_btime
,
i
=
d
.
dqb_itime
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
=
i
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
=
b
;
if
(
copy_to_user
((
struct
user_dqblk32
*
)
addr
,
&
d
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
}
return
0
;
}
#else
/* No conversion needed for new interface */
asmlinkage
long
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
return
sys_quotactl
(
cmd
,
special
,
id
,
addr
);
}
#endif
asmlinkage
long
asmlinkage
long
sys32_sched_rr_get_interval
(
pid_t
pid
,
struct
timespec32
*
interval
)
sys32_sched_rr_get_interval
(
pid_t
pid
,
struct
timespec32
*
interval
)
{
{
...
...
arch/s390x/kernel/linux32.c
View file @
704a6dfc
...
@@ -897,97 +897,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
...
@@ -897,97 +897,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
return
sys32_fcntl
(
fd
,
cmd
,
arg
);
return
sys32_fcntl
(
fd
,
cmd
,
arg
);
}
}
extern
asmlinkage
int
sys_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
);
#ifdef CONFIG_QIFACE_COMPAT
#ifdef CONFIG_QIFACE_V1
struct
user_dqblk32
{
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u32
dqb_curblocks
;
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v1c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
#define Q_COMP_SETQLIM Q_V1_SETQLIM
#define Q_COMP_SETUSE Q_V1_SETUSE
#else
struct
user_dqblk32
{
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u64
dqb_curspace
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v2c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
#define Q_COMP_SETQLIM Q_V2_SETQLIM
#define Q_COMP_SETUSE Q_V2_SETUSE
#endif
asmlinkage
int
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
int
cmds
=
cmd
>>
SUBCMDSHIFT
;
int
err
;
comp_dqblk_t
d
;
mm_segment_t
old_fs
;
char
*
spec
;
switch
(
cmds
)
{
case
Q_COMP_GETQUOTA
:
break
;
case
Q_COMP_SETQUOTA
:
case
Q_COMP_SETUSE
:
case
Q_COMP_SETQLIM
:
if
(
copy_from_user
(
&
d
,
(
struct
user_dqblk32
*
)
addr
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
d
.
dqb_itime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
;
d
.
dqb_btime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
;
break
;
default:
return
sys_quotactl
(
cmd
,
special
,
id
,
(
__kernel_caddr_t
)
addr
);
}
spec
=
getname
(
special
);
err
=
PTR_ERR
(
spec
);
if
(
IS_ERR
(
spec
))
return
err
;
old_fs
=
get_fs
();
set_fs
(
KERNEL_DS
);
err
=
sys_quotactl
(
cmd
,
(
const
char
*
)
spec
,
id
,
(
__kernel_caddr_t
)
&
d
);
set_fs
(
old_fs
);
putname
(
spec
);
if
(
err
)
return
err
;
if
(
cmds
==
Q_COMP_GETQUOTA
)
{
__kernel_time_t
b
=
d
.
dqb_btime
,
i
=
d
.
dqb_itime
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
=
i
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
=
b
;
if
(
copy_to_user
((
struct
user_dqblk32
*
)
addr
,
&
d
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
}
return
0
;
}
#else
/* No conversion needed for new interface */
asmlinkage
int
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
return
sys_quotactl
(
cmd
,
special
,
id
,
addr
);
}
#endif
static
inline
int
put_statfs
(
struct
statfs32
*
ubuf
,
struct
statfs
*
kbuf
)
static
inline
int
put_statfs
(
struct
statfs32
*
ubuf
,
struct
statfs
*
kbuf
)
{
{
int
err
;
int
err
;
...
...
arch/s390x/kernel/wrapper32.S
View file @
704a6dfc
...
@@ -586,7 +586,7 @@ sys32_quotactl_wrapper:
...
@@ -586,7 +586,7 @@ sys32_quotactl_wrapper:
llgtr
%
r3
,%
r3
#
const
char
*
llgtr
%
r3
,%
r3
#
const
char
*
lgfr
%
r4
,%
r4
#
int
lgfr
%
r4
,%
r4
#
int
llgtr
%
r5
,%
r5
#
caddr_t
llgtr
%
r5
,%
r5
#
caddr_t
jg
sys
32
_quotactl
#
branch
to
system
call
jg
sys_quotactl
#
branch
to
system
call
.
globl
sys32_getpgid_wrapper
.
globl
sys32_getpgid_wrapper
sys32_getpgid_wrapper
:
sys32_getpgid_wrapper
:
...
...
arch/sparc64/kernel/sys_sparc32.c
View file @
704a6dfc
...
@@ -889,97 +889,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
...
@@ -889,97 +889,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
return
sys32_fcntl
(
fd
,
cmd
,
arg
);
return
sys32_fcntl
(
fd
,
cmd
,
arg
);
}
}
extern
asmlinkage
int
sys_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
);
#ifdef CONFIG_QIFACE_COMPAT
#ifdef CONFIG_QIFACE_V1
struct
user_dqblk32
{
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u32
dqb_curblocks
;
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v1c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
#define Q_COMP_SETQLIM Q_V1_SETQLIM
#define Q_COMP_SETUSE Q_V1_SETUSE
#else
struct
user_dqblk32
{
__u32
dqb_ihardlimit
;
__u32
dqb_isoftlimit
;
__u32
dqb_curinodes
;
__u32
dqb_bhardlimit
;
__u32
dqb_bsoftlimit
;
__u64
dqb_curspace
;
__kernel_time_t32
dqb_btime
;
__kernel_time_t32
dqb_itime
;
};
typedef
struct
v2c_mem_dqblk
comp_dqblk_t
;
#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
#define Q_COMP_SETQLIM Q_V2_SETQLIM
#define Q_COMP_SETUSE Q_V2_SETUSE
#endif
asmlinkage
int
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
int
cmds
=
cmd
>>
SUBCMDSHIFT
;
int
err
;
comp_dqblk_t
d
;
mm_segment_t
old_fs
;
char
*
spec
;
switch
(
cmds
)
{
case
Q_COMP_GETQUOTA
:
break
;
case
Q_COMP_SETQUOTA
:
case
Q_COMP_SETUSE
:
case
Q_COMP_SETQLIM
:
if
(
copy_from_user
(
&
d
,
(
struct
user_dqblk32
*
)
addr
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
d
.
dqb_itime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
;
d
.
dqb_btime
=
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
;
break
;
default:
return
sys_quotactl
(
cmd
,
special
,
id
,
(
__kernel_caddr_t
)
addr
);
}
spec
=
getname
(
special
);
err
=
PTR_ERR
(
spec
);
if
(
IS_ERR
(
spec
))
return
err
;
old_fs
=
get_fs
();
set_fs
(
KERNEL_DS
);
err
=
sys_quotactl
(
cmd
,
(
const
char
*
)
spec
,
id
,
(
__kernel_caddr_t
)
&
d
);
set_fs
(
old_fs
);
putname
(
spec
);
if
(
err
)
return
err
;
if
(
cmds
==
Q_COMP_GETQUOTA
)
{
__kernel_time_t
b
=
d
.
dqb_btime
,
i
=
d
.
dqb_itime
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_itime
=
i
;
((
struct
user_dqblk32
*
)
&
d
)
->
dqb_btime
=
b
;
if
(
copy_to_user
((
struct
user_dqblk32
*
)
addr
,
&
d
,
sizeof
(
struct
user_dqblk32
)))
return
-
EFAULT
;
}
return
0
;
}
#else
/* No conversion needed for new interface */
asmlinkage
int
sys32_quotactl
(
int
cmd
,
const
char
*
special
,
int
id
,
caddr_t
addr
)
{
return
sys_quotactl
(
cmd
,
special
,
id
,
addr
);
}
#endif
static
inline
int
put_statfs
(
struct
statfs32
*
ubuf
,
struct
statfs
*
kbuf
)
static
inline
int
put_statfs
(
struct
statfs32
*
ubuf
,
struct
statfs
*
kbuf
)
{
{
int
err
;
int
err
;
...
...
arch/sparc64/kernel/systbls.S
View file @
704a6dfc
...
@@ -52,7 +52,7 @@ sys_call_table32:
...
@@ -52,7 +52,7 @@ sys_call_table32:
/*
150
*/
.
word
sys_nis_syscall
,
sys_nis_syscall
,
sys_nis_syscall
,
sys_poll
,
sys_getdents64
/*
150
*/
.
word
sys_nis_syscall
,
sys_nis_syscall
,
sys_nis_syscall
,
sys_poll
,
sys_getdents64
.
word
sys32_fcntl64
,
sys_nis_syscall
,
sys32_statfs
,
sys32_fstatfs
,
sys_oldumount
.
word
sys32_fcntl64
,
sys_nis_syscall
,
sys32_statfs
,
sys32_fstatfs
,
sys_oldumount
/*
160
*/
.
word
sys32_sched_setaffinity
,
sys32_sched_getaffinity
,
sys_getdomainname
,
sys_setdomainname
,
sys_nis_syscall
/*
160
*/
.
word
sys32_sched_setaffinity
,
sys32_sched_getaffinity
,
sys_getdomainname
,
sys_setdomainname
,
sys_nis_syscall
.
word
sys
32
_quotactl
,
sys_nis_syscall
,
sys32_mount
,
sys_ustat
,
sys_setxattr
.
word
sys_quotactl
,
sys_nis_syscall
,
sys32_mount
,
sys_ustat
,
sys_setxattr
/*
170
*/
.
word
sys_lsetxattr
,
sys_fsetxattr
,
sys_getxattr
,
sys_lgetxattr
,
sys32_getdents
/*
170
*/
.
word
sys_lsetxattr
,
sys_fsetxattr
,
sys_getxattr
,
sys_lgetxattr
,
sys32_getdents
.
word
sys_setsid
,
sys_fchdir
,
sys_fgetxattr
,
sys_listxattr
,
sys_llistxattr
.
word
sys_setsid
,
sys_fchdir
,
sys_fgetxattr
,
sys_listxattr
,
sys_llistxattr
/*
180
*/
.
word
sys_flistxattr
,
sys_removexattr
,
sys_lremovexattr
,
sys32_sigpending
,
sys32_query_module
/*
180
*/
.
word
sys_flistxattr
,
sys_removexattr
,
sys_lremovexattr
,
sys32_sigpending
,
sys32_query_module
...
...
fs/Config.help
View file @
704a6dfc
...
@@ -18,21 +18,6 @@ CONFIG_QFMT_V2
...
@@ -18,21 +18,6 @@ CONFIG_QFMT_V2
need this functionality say Y here. Note that you will need latest
need this functionality say Y here. Note that you will need latest
quota utilities for new quota format with this kernel.
quota utilities for new quota format with this kernel.
CONFIG_QIFACE_COMPAT
This option will enable old quota interface in kernel.
If you have old quota tools (version <= 3.04) and you don't want to
upgrade them say Y here.
CONFIG_QIFACE_V1
This is the oldest quota interface. It was used for old quota format.
If you have old quota tools and you use old quota format choose this
interface (if unsure, this interface is the best one to choose).
CONFIG_QIFACE_V2
This quota interface was used by VFS v0 quota format. If you need
support for VFS v0 quota format (eg. you're using quota on ReiserFS)
and you don't want to upgrade quota tools, choose this interface.
CONFIG_MINIX_FS
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about OS's.
Minix is a simple operating system used in many classes about OS's.
The minix file system (method to organize files on a hard disk
The minix file system (method to organize files on a hard disk
...
...
fs/Config.in
View file @
704a6dfc
...
@@ -7,11 +7,8 @@ comment 'File systems'
...
@@ -7,11 +7,8 @@ comment 'File systems'
bool 'Quota support' CONFIG_QUOTA
bool 'Quota support' CONFIG_QUOTA
dep_tristate ' Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA
dep_tristate ' Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA
dep_tristate ' VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
dep_tristate ' VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
dep_mbool ' Compatible quota interfaces' CONFIG_QIFACE_COMPAT $CONFIG_QUOTA
if [ "$CONFIG_QUOTA" = "y" ]; then
if [ "$CONFIG_QUOTA" = "y" -a "$CONFIG_QIFACE_COMPAT" = "y" ]; then
define_bool CONFIG_QUOTACTL y
choice ' Compatible quota interfaces' \
"Original CONFIG_QIFACE_V1 \
VFSv0 CONFIG_QIFACE_V2" Original
fi
fi
tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
...
...
fs/Makefile
View file @
704a6dfc
...
@@ -16,7 +16,7 @@ obj-y := open.o read_write.o devices.o file_table.o buffer.o \
...
@@ -16,7 +16,7 @@ obj-y := open.o read_write.o devices.o file_table.o buffer.o \
namei.o fcntl.o ioctl.o readdir.o
select
.o fifo.o locks.o
\
namei.o fcntl.o ioctl.o readdir.o
select
.o fifo.o locks.o
\
dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o
\
dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o
\
filesystems.o namespace.o seq_file.o xattr.o libfs.o
\
filesystems.o namespace.o seq_file.o xattr.o libfs.o
\
fs-writeback.o
quota.o
mpage.o
fs-writeback.o mpage.o
ifneq
($(CONFIG_NFSD),n)
ifneq
($(CONFIG_NFSD),n)
ifneq
($(CONFIG_NFSD),)
ifneq
($(CONFIG_NFSD),)
...
@@ -36,6 +36,7 @@ obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
...
@@ -36,6 +36,7 @@ obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
obj-$(CONFIG_QUOTA)
+=
dquot.o
obj-$(CONFIG_QUOTA)
+=
dquot.o
obj-$(CONFIG_QFMT_V1)
+=
quota_v1.o
obj-$(CONFIG_QFMT_V1)
+=
quota_v1.o
obj-$(CONFIG_QFMT_V2)
+=
quota_v2.o
obj-$(CONFIG_QFMT_V2)
+=
quota_v2.o
obj-$(CONFIG_QUOTACTL)
+=
quota.o
obj-$(CONFIG_PROC_FS)
+=
proc/
obj-$(CONFIG_PROC_FS)
+=
proc/
obj-y
+=
partitions/
obj-y
+=
partitions/
...
...
fs/dquot.c
View file @
704a6dfc
...
@@ -45,6 +45,10 @@
...
@@ -45,6 +45,10 @@
* Added dynamic quota structure allocation
* Added dynamic quota structure allocation
* Jan Kara <jack@suse.cz> 12/2000
* Jan Kara <jack@suse.cz> 12/2000
*
*
* Rewritten quota interface. Implemented new quota format and
* formats registering.
* Jan Kara, <jack@suse.cz>, 2001,2002
*
* (C) Copyright 1994 - 1997 Marco van Wieringen
* (C) Copyright 1994 - 1997 Marco van Wieringen
*/
*/
...
@@ -121,7 +125,7 @@ static void put_quota_format(struct quota_format_type *fmt)
...
@@ -121,7 +125,7 @@ static void put_quota_format(struct quota_format_type *fmt)
* Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
* Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
* and this list is searched whenever we need an available dquot. Dquots are
* and this list is searched whenever we need an available dquot. Dquots are
* removed from the list as soon as they are used again, and
* removed from the list as soon as they are used again, and
* dqstats
_array[DQSTATS_FREE]
gives the number of dquots on the list. When
* dqstats
.free_dquots
gives the number of dquots on the list. When
* dquot is invalidated it's completely released from memory.
* dquot is invalidated it's completely released from memory.
*
*
* Dquots with a specific identity (device, type and id) are placed on
* Dquots with a specific identity (device, type and id) are placed on
...
@@ -148,7 +152,7 @@ static LIST_HEAD(inuse_list);
...
@@ -148,7 +152,7 @@ static LIST_HEAD(inuse_list);
static
LIST_HEAD
(
free_dquots
);
static
LIST_HEAD
(
free_dquots
);
static
struct
list_head
dquot_hash
[
NR_DQHASH
];
static
struct
list_head
dquot_hash
[
NR_DQHASH
];
__u32
dqstats_array
[
DQSTATS_SIZE
]
;
struct
dqstats
dqstats
;
static
void
dqput
(
struct
dquot
*
);
static
void
dqput
(
struct
dquot
*
);
static
struct
dquot
*
dqduplicate
(
struct
dquot
*
);
static
struct
dquot
*
dqduplicate
(
struct
dquot
*
);
...
@@ -207,14 +211,14 @@ static inline struct dquot *find_dquot(unsigned int hashent, struct super_block
...
@@ -207,14 +211,14 @@ static inline struct dquot *find_dquot(unsigned int hashent, struct super_block
static
inline
void
put_dquot_head
(
struct
dquot
*
dquot
)
static
inline
void
put_dquot_head
(
struct
dquot
*
dquot
)
{
{
list_add
(
&
dquot
->
dq_free
,
&
free_dquots
);
list_add
(
&
dquot
->
dq_free
,
&
free_dquots
);
++
dqstats_array
[
DQSTATS_FREE
]
;
dqstats
.
free_dquots
++
;
}
}
/* Add a dquot to the tail of the free list */
/* Add a dquot to the tail of the free list */
static
inline
void
put_dquot_last
(
struct
dquot
*
dquot
)
static
inline
void
put_dquot_last
(
struct
dquot
*
dquot
)
{
{
list_add
(
&
dquot
->
dq_free
,
free_dquots
.
prev
);
list_add
(
&
dquot
->
dq_free
,
free_dquots
.
prev
);
++
dqstats_array
[
DQSTATS_FREE
]
;
dqstats
.
free_dquots
++
;
}
}
/* Move dquot to the head of free list (it must be already on it) */
/* Move dquot to the head of free list (it must be already on it) */
...
@@ -230,7 +234,7 @@ static inline void remove_free_dquot(struct dquot *dquot)
...
@@ -230,7 +234,7 @@ static inline void remove_free_dquot(struct dquot *dquot)
return
;
return
;
list_del
(
&
dquot
->
dq_free
);
list_del
(
&
dquot
->
dq_free
);
INIT_LIST_HEAD
(
&
dquot
->
dq_free
);
INIT_LIST_HEAD
(
&
dquot
->
dq_free
);
--
dqstats_array
[
DQSTATS_FREE
]
;
dqstats
.
free_dquots
--
;
}
}
static
inline
void
put_inuse
(
struct
dquot
*
dquot
)
static
inline
void
put_inuse
(
struct
dquot
*
dquot
)
...
@@ -238,12 +242,12 @@ static inline void put_inuse(struct dquot *dquot)
...
@@ -238,12 +242,12 @@ static inline void put_inuse(struct dquot *dquot)
/* We add to the back of inuse list so we don't have to restart
/* We add to the back of inuse list so we don't have to restart
* when traversing this list and we block */
* when traversing this list and we block */
list_add
(
&
dquot
->
dq_inuse
,
inuse_list
.
prev
);
list_add
(
&
dquot
->
dq_inuse
,
inuse_list
.
prev
);
++
dqstats_array
[
DQSTATS_ALLOCATED
]
;
dqstats
.
allocated_dquots
++
;
}
}
static
inline
void
remove_inuse
(
struct
dquot
*
dquot
)
static
inline
void
remove_inuse
(
struct
dquot
*
dquot
)
{
{
--
dqstats_array
[
DQSTATS_ALLOCATED
]
;
dqstats
.
allocated_dquots
--
;
list_del
(
&
dquot
->
dq_inuse
);
list_del
(
&
dquot
->
dq_inuse
);
}
}
...
@@ -403,7 +407,7 @@ static int vfs_quota_sync(struct super_block *sb, int type)
...
@@ -403,7 +407,7 @@ static int vfs_quota_sync(struct super_block *sb, int type)
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
for
(
cnt
=
0
;
cnt
<
MAXQUOTAS
;
cnt
++
)
if
((
cnt
==
type
||
type
==
-
1
)
&&
sb_has_quota_enabled
(
sb
,
cnt
)
&&
info_dirty
(
&
dqopt
->
info
[
cnt
]))
if
((
cnt
==
type
||
type
==
-
1
)
&&
sb_has_quota_enabled
(
sb
,
cnt
)
&&
info_dirty
(
&
dqopt
->
info
[
cnt
]))
dqopt
->
ops
[
cnt
]
->
write_file_info
(
sb
,
cnt
);
dqopt
->
ops
[
cnt
]
->
write_file_info
(
sb
,
cnt
);
++
dqstats_array
[
DQSTATS_SYNCS
]
;
dqstats
.
syncs
++
;
return
0
;
return
0
;
}
}
...
@@ -491,7 +495,7 @@ int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
...
@@ -491,7 +495,7 @@ int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
int
count
=
0
;
int
count
=
0
;
lock_kernel
();
lock_kernel
();
count
=
dqstats
_array
[
DQSTATS_FREE
]
/
priority
;
count
=
dqstats
.
free_dquots
/
priority
;
prune_dqcache
(
count
);
prune_dqcache
(
count
);
unlock_kernel
();
unlock_kernel
();
kmem_cache_shrink
(
dquot_cachep
);
kmem_cache_shrink
(
dquot_cachep
);
...
@@ -517,7 +521,7 @@ static void dqput(struct dquot *dquot)
...
@@ -517,7 +521,7 @@ static void dqput(struct dquot *dquot)
}
}
#endif
#endif
++
dqstats_array
[
DQSTATS_DROPS
]
;
dqstats
.
drops
++
;
we_slept:
we_slept:
if
(
dquot
->
dq_dup_ref
&&
dquot
->
dq_count
-
dquot
->
dq_dup_ref
<=
1
)
{
/* Last unduplicated reference? */
if
(
dquot
->
dq_dup_ref
&&
dquot
->
dq_count
-
dquot
->
dq_dup_ref
<=
1
)
{
/* Last unduplicated reference? */
__wait_dup_drop
(
dquot
);
__wait_dup_drop
(
dquot
);
...
@@ -597,7 +601,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
...
@@ -597,7 +601,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
if
(
!
dquot
->
dq_count
)
if
(
!
dquot
->
dq_count
)
remove_free_dquot
(
dquot
);
remove_free_dquot
(
dquot
);
get_dquot_ref
(
dquot
);
get_dquot_ref
(
dquot
);
++
dqstats_array
[
DQSTATS_CACHE_HITS
]
;
dqstats
.
cache_hits
++
;
wait_on_dquot
(
dquot
);
wait_on_dquot
(
dquot
);
if
(
empty
)
if
(
empty
)
dqput
(
empty
);
dqput
(
empty
);
...
@@ -609,7 +613,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
...
@@ -609,7 +613,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
return
NODQUOT
;
return
NODQUOT
;
}
}
++
dquot
->
dq_referenced
;
++
dquot
->
dq_referenced
;
++
dqstats_array
[
DQSTATS_LOOKUPS
]
;
dqstats
.
lookups
++
;
return
dquot
;
return
dquot
;
}
}
...
@@ -629,7 +633,7 @@ static struct dquot *dqduplicate(struct dquot *dquot)
...
@@ -629,7 +633,7 @@ static struct dquot *dqduplicate(struct dquot *dquot)
printk
(
KERN_ERR
"VFS: dqduplicate(): Locked quota to be duplicated!
\n
"
);
printk
(
KERN_ERR
"VFS: dqduplicate(): Locked quota to be duplicated!
\n
"
);
get_dquot_dup_ref
(
dquot
);
get_dquot_dup_ref
(
dquot
);
dquot
->
dq_referenced
++
;
dquot
->
dq_referenced
++
;
++
dqstats_array
[
DQSTATS_LOOKUPS
]
;
dqstats
.
lookups
++
;
return
dquot
;
return
dquot
;
}
}
...
@@ -645,7 +649,7 @@ static void dqputduplicate(struct dquot *dquot)
...
@@ -645,7 +649,7 @@ static void dqputduplicate(struct dquot *dquot)
if
(
!
dquot
->
dq_dup_ref
)
if
(
!
dquot
->
dq_dup_ref
)
wake_up
(
&
dquot
->
dq_wait_free
);
wake_up
(
&
dquot
->
dq_wait_free
);
put_dquot_ref
(
dquot
);
put_dquot_ref
(
dquot
);
++
dqstats_array
[
DQSTATS_DROPS
]
;
dqstats
.
drops
++
;
}
}
static
int
dqinit_needed
(
struct
inode
*
inode
,
int
type
)
static
int
dqinit_needed
(
struct
inode
*
inode
,
int
type
)
...
@@ -1295,7 +1299,7 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
...
@@ -1295,7 +1299,7 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
int
error
;
int
error
;
if
(
!
fmt
)
if
(
!
fmt
)
return
-
E
INVAL
;
return
-
E
SRCH
;
if
(
is_enabled
(
dqopt
,
type
))
{
if
(
is_enabled
(
dqopt
,
type
))
{
error
=
-
EBUSY
;
error
=
-
EBUSY
;
goto
out_fmt
;
goto
out_fmt
;
...
@@ -1437,7 +1441,7 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
...
@@ -1437,7 +1441,7 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
}
}
/* Generic routine for getting common part of quota file information */
/* Generic routine for getting common part of quota file information */
int
vfs_get_info
(
struct
super_block
*
sb
,
int
type
,
struct
if_dqinfo
*
ii
)
int
vfs_get_
dq
info
(
struct
super_block
*
sb
,
int
type
,
struct
if_dqinfo
*
ii
)
{
{
struct
mem_dqinfo
*
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
struct
mem_dqinfo
*
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
...
@@ -1449,7 +1453,7 @@ int vfs_get_info(struct super_block *sb, int type, struct if_dqinfo *ii)
...
@@ -1449,7 +1453,7 @@ int vfs_get_info(struct super_block *sb, int type, struct if_dqinfo *ii)
}
}
/* Generic routine for setting common part of quota file information */
/* Generic routine for setting common part of quota file information */
int
vfs_set_info
(
struct
super_block
*
sb
,
int
type
,
struct
if_dqinfo
*
ii
)
int
vfs_set_
dq
info
(
struct
super_block
*
sb
,
int
type
,
struct
if_dqinfo
*
ii
)
{
{
struct
mem_dqinfo
*
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
struct
mem_dqinfo
*
mi
=
sb_dqopt
(
sb
)
->
info
+
type
;
...
@@ -1467,18 +1471,30 @@ struct quotactl_ops vfs_quotactl_ops = {
...
@@ -1467,18 +1471,30 @@ struct quotactl_ops vfs_quotactl_ops = {
quota_on:
vfs_quota_on
,
quota_on:
vfs_quota_on
,
quota_off:
vfs_quota_off
,
quota_off:
vfs_quota_off
,
quota_sync:
vfs_quota_sync
,
quota_sync:
vfs_quota_sync
,
get_info:
vfs_get_info
,
get_info:
vfs_get_
dq
info
,
set_info:
vfs_set_info
,
set_info:
vfs_set_
dq
info
,
get_dqblk:
vfs_get_dqblk
,
get_dqblk:
vfs_get_dqblk
,
set_dqblk:
vfs_set_dqblk
set_dqblk:
vfs_set_dqblk
};
};
static
ctl_table
fs_dqstats_table
[]
=
{
{
FS_DQ_LOOKUPS
,
"lookups"
,
&
dqstats
.
lookups
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_DROPS
,
"drops"
,
&
dqstats
.
drops
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_READS
,
"reads"
,
&
dqstats
.
reads
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_WRITES
,
"writes"
,
&
dqstats
.
writes
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_CACHE_HITS
,
"cache_hits"
,
&
dqstats
.
cache_hits
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_ALLOCATED
,
"allocated_dquots"
,
&
dqstats
.
allocated_dquots
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_FREE
,
"free_dquots"
,
&
dqstats
.
free_dquots
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQ_SYNCS
,
"syncs"
,
&
dqstats
.
syncs
,
sizeof
(
int
),
0444
,
NULL
,
&
proc_dointvec
},
{},
};
static
ctl_table
fs_table
[]
=
{
static
ctl_table
fs_table
[]
=
{
{
FS_DQSTATS
,
"
dqstats"
,
dqstats_array
,
sizeof
(
dqstats_array
),
0444
,
NULL
,
&
proc_dointvec
},
{
FS_DQSTATS
,
"
quota"
,
NULL
,
0
,
0555
,
fs_dqstats_table
},
{},
{},
};
};
static
ctl_table
dquot
_table
[]
=
{
static
ctl_table
sys
_table
[]
=
{
{
CTL_FS
,
"fs"
,
NULL
,
0
,
0555
,
fs_table
},
{
CTL_FS
,
"fs"
,
NULL
,
0
,
0555
,
fs_table
},
{},
{},
};
};
...
@@ -1487,7 +1503,7 @@ static int __init dquot_init(void)
...
@@ -1487,7 +1503,7 @@ static int __init dquot_init(void)
{
{
int
i
;
int
i
;
register_sysctl_table
(
dquot
_table
,
0
);
register_sysctl_table
(
sys
_table
,
0
);
for
(
i
=
0
;
i
<
NR_DQHASH
;
i
++
)
for
(
i
=
0
;
i
<
NR_DQHASH
;
i
++
)
INIT_LIST_HEAD
(
dquot_hash
+
i
);
INIT_LIST_HEAD
(
dquot_hash
+
i
);
printk
(
KERN_NOTICE
"VFS: Disk quotas v%s
\n
"
,
__DQUOT_VERSION__
);
printk
(
KERN_NOTICE
"VFS: Disk quotas v%s
\n
"
,
__DQUOT_VERSION__
);
...
@@ -1498,4 +1514,4 @@ __initcall(dquot_init);
...
@@ -1498,4 +1514,4 @@ __initcall(dquot_init);
EXPORT_SYMBOL
(
register_quota_format
);
EXPORT_SYMBOL
(
register_quota_format
);
EXPORT_SYMBOL
(
unregister_quota_format
);
EXPORT_SYMBOL
(
unregister_quota_format
);
EXPORT_SYMBOL
(
dqstats
_array
);
EXPORT_SYMBOL
(
dqstats
);
fs/quota.c
View file @
704a6dfc
...
@@ -6,16 +6,12 @@
...
@@ -6,16 +6,12 @@
*/
*/
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <asm/current.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <linux/namei.h>
#ifdef CONFIG_QIFACE_COMPAT
#include <linux/quotacompat.h>
#endif
/* Check validity of quotactl */
/* Check validity of quotactl */
static
int
check_quotactl_valid
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
)
static
int
check_quotactl_valid
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
)
...
@@ -234,381 +230,6 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, cadd
...
@@ -234,381 +230,6 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, cadd
return
0
;
return
0
;
}
}
#ifdef CONFIG_QIFACE_COMPAT
static
int
check_compat_quotactl_valid
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
)
{
if
(
type
>=
MAXQUOTAS
)
return
-
EINVAL
;
/* Is operation supported? */
/* sb==NULL for GETSTATS calls */
if
(
sb
&&
!
sb
->
s_qcop
)
return
-
ENOSYS
;
switch
(
cmd
)
{
case
Q_COMP_QUOTAON
:
if
(
!
sb
->
s_qcop
->
quota_on
)
return
-
ENOSYS
;
break
;
case
Q_COMP_QUOTAOFF
:
if
(
!
sb
->
s_qcop
->
quota_off
)
return
-
ENOSYS
;
break
;
case
Q_COMP_SYNC
:
if
(
!
sb
->
s_qcop
->
quota_sync
)
return
-
ENOSYS
;
break
;
#ifdef CONFIG_QIFACE_V2
case
Q_V2_SETFLAGS
:
case
Q_V2_SETGRACE
:
case
Q_V2_SETINFO
:
if
(
!
sb
->
s_qcop
->
set_info
)
return
-
ENOSYS
;
break
;
case
Q_V2_GETINFO
:
if
(
!
sb
->
s_qcop
->
get_info
)
return
-
ENOSYS
;
break
;
case
Q_V2_SETQLIM
:
case
Q_V2_SETUSE
:
case
Q_V2_SETQUOTA
:
if
(
!
sb
->
s_qcop
->
set_dqblk
)
return
-
ENOSYS
;
break
;
case
Q_V2_GETQUOTA
:
if
(
!
sb
->
s_qcop
->
get_dqblk
)
return
-
ENOSYS
;
break
;
case
Q_V2_GETSTATS
:
return
0
;
/* GETSTATS need no other checks */
#endif
#ifdef CONFIG_QIFACE_V1
case
Q_V1_SETQLIM
:
case
Q_V1_SETUSE
:
case
Q_V1_SETQUOTA
:
if
(
!
sb
->
s_qcop
->
set_dqblk
)
return
-
ENOSYS
;
break
;
case
Q_V1_GETQUOTA
:
if
(
!
sb
->
s_qcop
->
get_dqblk
)
return
-
ENOSYS
;
break
;
case
Q_V1_RSQUASH
:
if
(
!
sb
->
s_qcop
->
set_info
)
return
-
ENOSYS
;
break
;
case
Q_V1_GETSTATS
:
return
0
;
/* GETSTATS need no other checks */
#endif
default:
return
-
EINVAL
;
}
/* Is quota turned on for commands which need it? */
switch
(
cmd
)
{
case
Q_V2_SETFLAGS
:
case
Q_V2_SETGRACE
:
case
Q_V2_SETINFO
:
case
Q_V2_GETINFO
:
case
Q_COMP_QUOTAOFF
:
case
Q_V1_RSQUASH
:
case
Q_V1_SETQUOTA
:
case
Q_V1_SETQLIM
:
case
Q_V1_SETUSE
:
case
Q_V2_SETQUOTA
:
/* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
case
Q_V2_SETUSE
:
case
Q_V1_GETQUOTA
:
case
Q_V2_GETQUOTA
:
if
(
!
sb_has_quota_enabled
(
sb
,
type
))
return
-
ESRCH
;
}
#ifdef CONFIG_QIFACE_V1
if
(
cmd
!=
Q_COMP_QUOTAON
&&
cmd
!=
Q_COMP_QUOTAOFF
&&
cmd
!=
Q_COMP_SYNC
&&
sb_dqopt
(
sb
)
->
info
[
type
].
dqi_format
->
qf_fmt_id
!=
QFMT_VFS_OLD
)
#else
if
(
cmd
!=
Q_COMP_QUOTAON
&&
cmd
!=
Q_COMP_QUOTAOFF
&&
cmd
!=
Q_COMP_SYNC
&&
sb_dqopt
(
sb
)
->
info
[
type
].
dqi_format
->
qf_fmt_id
!=
QFMT_VFS_V0
)
#endif
return
-
ESRCH
;
/* Check privileges */
if
(
cmd
==
Q_V1_GETQUOTA
||
cmd
==
Q_V2_GETQUOTA
)
{
if
(((
type
==
USRQUOTA
&&
current
->
euid
!=
id
)
||
(
type
==
GRPQUOTA
&&
!
in_egroup_p
(
id
)))
&&
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
}
else
if
(
cmd
!=
Q_V1_GETSTATS
&&
cmd
!=
Q_V2_GETSTATS
&&
cmd
!=
Q_V2_GETINFO
&&
cmd
!=
Q_COMP_SYNC
)
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
return
0
;
}
#ifdef CONFIG_QIFACE_V1
static
int
v1_set_rsquash
(
struct
super_block
*
sb
,
int
type
,
int
flag
)
{
struct
if_dqinfo
info
;
info
.
dqi_valid
=
IIF_FLAGS
;
info
.
dqi_flags
=
flag
?
V1_DQF_RSQUASH
:
0
;
return
sb
->
s_qcop
->
set_info
(
sb
,
type
,
&
info
);
}
static
int
v1_get_dqblk
(
struct
super_block
*
sb
,
int
type
,
qid_t
id
,
struct
v1c_mem_dqblk
*
mdq
)
{
struct
if_dqblk
idq
;
int
ret
;
if
((
ret
=
sb
->
s_qcop
->
get_dqblk
(
sb
,
type
,
id
,
&
idq
))
<
0
)
return
ret
;
mdq
->
dqb_ihardlimit
=
idq
.
dqb_ihardlimit
;
mdq
->
dqb_isoftlimit
=
idq
.
dqb_isoftlimit
;
mdq
->
dqb_curinodes
=
idq
.
dqb_curinodes
;
mdq
->
dqb_bhardlimit
=
idq
.
dqb_bhardlimit
;
mdq
->
dqb_bsoftlimit
=
idq
.
dqb_bsoftlimit
;
mdq
->
dqb_curblocks
=
toqb
(
idq
.
dqb_curspace
);
mdq
->
dqb_itime
=
idq
.
dqb_itime
;
mdq
->
dqb_btime
=
idq
.
dqb_btime
;
if
(
id
==
0
)
{
/* Times for id 0 are in fact grace times */
struct
if_dqinfo
info
;
if
((
ret
=
sb
->
s_qcop
->
get_info
(
sb
,
type
,
&
info
))
<
0
)
return
ret
;
mdq
->
dqb_btime
=
info
.
dqi_bgrace
;
mdq
->
dqb_itime
=
info
.
dqi_igrace
;
}
return
0
;
}
static
int
v1_set_dqblk
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
,
struct
v1c_mem_dqblk
*
mdq
)
{
struct
if_dqblk
idq
;
int
ret
;
idq
.
dqb_valid
=
0
;
if
(
cmd
==
Q_V1_SETQUOTA
||
cmd
==
Q_V1_SETQLIM
)
{
idq
.
dqb_ihardlimit
=
mdq
->
dqb_ihardlimit
;
idq
.
dqb_isoftlimit
=
mdq
->
dqb_isoftlimit
;
idq
.
dqb_bhardlimit
=
mdq
->
dqb_bhardlimit
;
idq
.
dqb_bsoftlimit
=
mdq
->
dqb_bsoftlimit
;
idq
.
dqb_valid
|=
QIF_LIMITS
;
}
if
(
cmd
==
Q_V1_SETQUOTA
||
cmd
==
Q_V1_SETUSE
)
{
idq
.
dqb_curinodes
=
mdq
->
dqb_curinodes
;
idq
.
dqb_curspace
=
((
qsize_t
)
mdq
->
dqb_curblocks
)
<<
QUOTABLOCK_BITS
;
idq
.
dqb_valid
|=
QIF_USAGE
;
}
ret
=
sb
->
s_qcop
->
set_dqblk
(
sb
,
type
,
id
,
&
idq
);
if
(
!
ret
&&
id
==
0
&&
cmd
==
Q_V1_SETQUOTA
)
{
/* Times for id 0 are in fact grace times */
struct
if_dqinfo
info
;
info
.
dqi_bgrace
=
mdq
->
dqb_btime
;
info
.
dqi_igrace
=
mdq
->
dqb_itime
;
info
.
dqi_valid
=
IIF_BGRACE
|
IIF_IGRACE
;
ret
=
sb
->
s_qcop
->
set_info
(
sb
,
type
,
&
info
);
}
return
ret
;
}
static
void
v1_get_stats
(
struct
v1c_dqstats
*
dst
)
{
memcpy
(
dst
,
&
dqstats_array
,
sizeof
(
dqstats_array
));
}
#endif
#ifdef CONFIG_QIFACE_V2
static
int
v2_get_info
(
struct
super_block
*
sb
,
int
type
,
struct
v2c_mem_dqinfo
*
oinfo
)
{
struct
if_dqinfo
info
;
int
ret
;
if
((
ret
=
sb
->
s_qcop
->
get_info
(
sb
,
type
,
&
info
))
<
0
)
return
ret
;
oinfo
->
dqi_bgrace
=
info
.
dqi_bgrace
;
oinfo
->
dqi_igrace
=
info
.
dqi_igrace
;
oinfo
->
dqi_flags
=
info
.
dqi_flags
;
oinfo
->
dqi_blocks
=
sb_dqopt
(
sb
)
->
info
[
type
].
u
.
v2_i
.
dqi_blocks
;
oinfo
->
dqi_free_blk
=
sb_dqopt
(
sb
)
->
info
[
type
].
u
.
v2_i
.
dqi_free_blk
;
oinfo
->
dqi_free_entry
=
sb_dqopt
(
sb
)
->
info
[
type
].
u
.
v2_i
.
dqi_free_entry
;
return
0
;
}
static
int
v2_set_info
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
struct
v2c_mem_dqinfo
*
oinfo
)
{
struct
if_dqinfo
info
;
info
.
dqi_valid
=
0
;
if
(
cmd
==
Q_V2_SETGRACE
||
cmd
==
Q_V2_SETINFO
)
{
info
.
dqi_bgrace
=
oinfo
->
dqi_bgrace
;
info
.
dqi_igrace
=
oinfo
->
dqi_igrace
;
info
.
dqi_valid
|=
IIF_BGRACE
|
IIF_IGRACE
;
}
if
(
cmd
==
Q_V2_SETFLAGS
||
cmd
==
Q_V2_SETINFO
)
{
info
.
dqi_flags
=
oinfo
->
dqi_flags
;
info
.
dqi_valid
|=
IIF_FLAGS
;
}
/* We don't simulate deadly effects of setting other parameters ;-) */
return
sb
->
s_qcop
->
set_info
(
sb
,
type
,
&
info
);
}
static
int
v2_get_dqblk
(
struct
super_block
*
sb
,
int
type
,
qid_t
id
,
struct
v2c_mem_dqblk
*
mdq
)
{
struct
if_dqblk
idq
;
int
ret
;
if
((
ret
=
sb
->
s_qcop
->
get_dqblk
(
sb
,
type
,
id
,
&
idq
))
<
0
)
return
ret
;
mdq
->
dqb_ihardlimit
=
idq
.
dqb_ihardlimit
;
mdq
->
dqb_isoftlimit
=
idq
.
dqb_isoftlimit
;
mdq
->
dqb_curinodes
=
idq
.
dqb_curinodes
;
mdq
->
dqb_bhardlimit
=
idq
.
dqb_bhardlimit
;
mdq
->
dqb_bsoftlimit
=
idq
.
dqb_bsoftlimit
;
mdq
->
dqb_curspace
=
idq
.
dqb_curspace
;
mdq
->
dqb_itime
=
idq
.
dqb_itime
;
mdq
->
dqb_btime
=
idq
.
dqb_btime
;
return
0
;
}
static
int
v2_set_dqblk
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
,
struct
v2c_mem_dqblk
*
mdq
)
{
struct
if_dqblk
idq
;
idq
.
dqb_valid
=
0
;
if
(
cmd
==
Q_V2_SETQUOTA
||
cmd
==
Q_V2_SETQLIM
)
{
idq
.
dqb_ihardlimit
=
mdq
->
dqb_ihardlimit
;
idq
.
dqb_isoftlimit
=
mdq
->
dqb_isoftlimit
;
idq
.
dqb_bhardlimit
=
mdq
->
dqb_bhardlimit
;
idq
.
dqb_bsoftlimit
=
mdq
->
dqb_bsoftlimit
;
idq
.
dqb_valid
|=
QIF_LIMITS
;
}
if
(
cmd
==
Q_V2_SETQUOTA
||
cmd
==
Q_V2_SETUSE
)
{
idq
.
dqb_curinodes
=
mdq
->
dqb_curinodes
;
idq
.
dqb_curspace
=
mdq
->
dqb_curspace
;
idq
.
dqb_valid
|=
QIF_USAGE
;
}
return
sb
->
s_qcop
->
set_dqblk
(
sb
,
type
,
id
,
&
idq
);
}
static
void
v2_get_stats
(
struct
v2c_dqstats
*
dst
)
{
memcpy
(
dst
,
&
dqstats_array
,
sizeof
(
dqstats_array
));
dst
->
version
=
__DQUOT_NUM_VERSION__
;
}
#endif
/* Handle requests to old interface */
static
int
do_compat_quotactl
(
struct
super_block
*
sb
,
int
type
,
int
cmd
,
qid_t
id
,
caddr_t
addr
)
{
int
ret
;
switch
(
cmd
)
{
case
Q_COMP_QUOTAON
:
{
char
*
pathname
;
if
(
IS_ERR
(
pathname
=
getname
(
addr
)))
return
PTR_ERR
(
pathname
);
#ifdef CONFIG_QIFACE_V1
ret
=
sb
->
s_qcop
->
quota_on
(
sb
,
type
,
QFMT_VFS_OLD
,
pathname
);
#else
ret
=
sb
->
s_qcop
->
quota_on
(
sb
,
type
,
QFMT_VFS_V0
,
pathname
);
#endif
putname
(
pathname
);
return
ret
;
}
case
Q_COMP_QUOTAOFF
:
return
sb
->
s_qcop
->
quota_off
(
sb
,
type
);
case
Q_COMP_SYNC
:
return
sb
->
s_qcop
->
quota_sync
(
sb
,
type
);
#ifdef CONFIG_QIFACE_V1
case
Q_V1_RSQUASH
:
{
int
flag
;
if
(
copy_from_user
(
&
flag
,
addr
,
sizeof
(
flag
)))
return
-
EFAULT
;
return
v1_set_rsquash
(
sb
,
type
,
flag
);
}
case
Q_V1_GETQUOTA
:
{
struct
v1c_mem_dqblk
mdq
;
if
((
ret
=
v1_get_dqblk
(
sb
,
type
,
id
,
&
mdq
)))
return
ret
;
if
(
copy_to_user
(
addr
,
&
mdq
,
sizeof
(
mdq
)))
return
-
EFAULT
;
return
0
;
}
case
Q_V1_SETQLIM
:
case
Q_V1_SETUSE
:
case
Q_V1_SETQUOTA
:
{
struct
v1c_mem_dqblk
mdq
;
if
(
copy_from_user
(
&
mdq
,
addr
,
sizeof
(
mdq
)))
return
-
EFAULT
;
return
v1_set_dqblk
(
sb
,
type
,
cmd
,
id
,
&
mdq
);
}
case
Q_V1_GETSTATS
:
{
struct
v1c_dqstats
dst
;
v1_get_stats
(
&
dst
);
if
(
copy_to_user
(
addr
,
&
dst
,
sizeof
(
dst
)))
return
-
EFAULT
;
return
0
;
}
#endif
#ifdef CONFIG_QIFACE_V2
case
Q_V2_GETINFO
:
{
struct
v2c_mem_dqinfo
info
;
if
((
ret
=
v2_get_info
(
sb
,
type
,
&
info
)))
return
ret
;
if
(
copy_to_user
(
addr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
case
Q_V2_SETFLAGS
:
case
Q_V2_SETGRACE
:
case
Q_V2_SETINFO
:
{
struct
v2c_mem_dqinfo
info
;
if
(
copy_from_user
(
&
info
,
addr
,
sizeof
(
info
)))
return
-
EFAULT
;
return
v2_set_info
(
sb
,
type
,
cmd
,
&
info
);
}
case
Q_V2_GETQUOTA
:
{
struct
v2c_mem_dqblk
mdq
;
if
((
ret
=
v2_get_dqblk
(
sb
,
type
,
id
,
&
mdq
)))
return
ret
;
if
(
copy_to_user
(
addr
,
&
mdq
,
sizeof
(
mdq
)))
return
-
EFAULT
;
return
0
;
}
case
Q_V2_SETUSE
:
case
Q_V2_SETQLIM
:
case
Q_V2_SETQUOTA
:
{
struct
v2c_mem_dqblk
mdq
;
if
(
copy_from_user
(
&
mdq
,
addr
,
sizeof
(
mdq
)))
return
-
EFAULT
;
return
v2_set_dqblk
(
sb
,
type
,
cmd
,
id
,
&
mdq
);
}
case
Q_V2_GETSTATS
:
{
struct
v2c_dqstats
dst
;
v2_get_stats
(
&
dst
);
if
(
copy_to_user
(
addr
,
&
dst
,
sizeof
(
dst
)))
return
-
EFAULT
;
return
0
;
}
#endif
}
BUG
();
return
0
;
}
#endif
/* Macros for short-circuiting the compatibility tests */
#define NEW_COMMAND(c) ((c) & (0x80 << 16))
#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
/*
/*
* This is the system call interface. This communicates with
* This is the system call interface. This communicates with
* the user-level programs. Currently this only supports diskquota
* the user-level programs. Currently this only supports diskquota
...
@@ -625,25 +246,11 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, ca
...
@@ -625,25 +246,11 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, ca
cmds
=
cmd
>>
SUBCMDSHIFT
;
cmds
=
cmd
>>
SUBCMDSHIFT
;
type
=
cmd
&
SUBCMDMASK
;
type
=
cmd
&
SUBCMDMASK
;
#ifdef CONFIG_QIFACE_COMPAT
if
(
cmds
!=
Q_V1_GETSTATS
&&
cmds
!=
Q_V2_GETSTATS
&&
IS_ERR
(
sb
=
resolve_dev
(
special
)))
{
ret
=
PTR_ERR
(
sb
);
sb
=
NULL
;
goto
out
;
}
if
(
!
NEW_COMMAND
(
cmds
)
&&
!
XQM_COMMAND
(
cmds
))
{
if
((
ret
=
check_compat_quotactl_valid
(
sb
,
type
,
cmds
,
id
))
<
0
)
goto
out
;
ret
=
do_compat_quotactl
(
sb
,
type
,
cmds
,
id
,
addr
);
goto
out
;
}
#else
if
(
IS_ERR
(
sb
=
resolve_dev
(
special
)))
{
if
(
IS_ERR
(
sb
=
resolve_dev
(
special
)))
{
ret
=
PTR_ERR
(
sb
);
ret
=
PTR_ERR
(
sb
);
sb
=
NULL
;
sb
=
NULL
;
goto
out
;
goto
out
;
}
}
#endif
if
((
ret
=
check_quotactl_valid
(
sb
,
type
,
cmds
,
id
))
<
0
)
if
((
ret
=
check_quotactl_valid
(
sb
,
type
,
cmds
,
id
))
<
0
)
goto
out
;
goto
out
;
ret
=
do_quotactl
(
sb
,
type
,
cmds
,
id
,
addr
);
ret
=
do_quotactl
(
sb
,
type
,
cmds
,
id
,
addr
);
...
...
fs/quota_v1.c
View file @
704a6dfc
...
@@ -57,7 +57,7 @@ static int v1_read_dqblk(struct dquot *dquot)
...
@@ -57,7 +57,7 @@ static int v1_read_dqblk(struct dquot *dquot)
if
(
dquot
->
dq_dqb
.
dqb_bhardlimit
==
0
&&
dquot
->
dq_dqb
.
dqb_bsoftlimit
==
0
&&
if
(
dquot
->
dq_dqb
.
dqb_bhardlimit
==
0
&&
dquot
->
dq_dqb
.
dqb_bsoftlimit
==
0
&&
dquot
->
dq_dqb
.
dqb_ihardlimit
==
0
&&
dquot
->
dq_dqb
.
dqb_isoftlimit
==
0
)
dquot
->
dq_dqb
.
dqb_ihardlimit
==
0
&&
dquot
->
dq_dqb
.
dqb_isoftlimit
==
0
)
dquot
->
dq_flags
|=
DQ_FAKE
;
dquot
->
dq_flags
|=
DQ_FAKE
;
++
dqstats_array
[
DQSTATS_READS
]
;
dqstats
.
reads
++
;
return
0
;
return
0
;
}
}
...
@@ -101,7 +101,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
...
@@ -101,7 +101,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
out:
out:
set_fs
(
fs
);
set_fs
(
fs
);
++
dqstats_array
[
DQSTATS_WRITES
]
;
dqstats
.
writes
++
;
return
ret
;
return
ret
;
}
}
...
@@ -234,6 +234,8 @@ static void __exit exit_v1_quota_format(void)
...
@@ -234,6 +234,8 @@ static void __exit exit_v1_quota_format(void)
unregister_quota_format
(
&
v1_quota_format
);
unregister_quota_format
(
&
v1_quota_format
);
}
}
EXPORT_NO_SYMBOLS
;
module_init
(
init_v1_quota_format
);
module_init
(
init_v1_quota_format
);
module_exit
(
exit_v1_quota_format
);
module_exit
(
exit_v1_quota_format
);
fs/quota_v2.c
View file @
704a6dfc
...
@@ -430,7 +430,7 @@ static int v2_write_dquot(struct dquot *dquot)
...
@@ -430,7 +430,7 @@ static int v2_write_dquot(struct dquot *dquot)
}
}
else
else
ret
=
0
;
ret
=
0
;
++
dqstats_array
[
DQSTATS_WRITES
]
;
dqstats
.
writes
++
;
return
ret
;
return
ret
;
}
}
...
@@ -645,7 +645,7 @@ static int v2_read_dquot(struct dquot *dquot)
...
@@ -645,7 +645,7 @@ static int v2_read_dquot(struct dquot *dquot)
set_fs
(
fs
);
set_fs
(
fs
);
disk2memdqb
(
&
dquot
->
dq_dqb
,
&
ddquot
);
disk2memdqb
(
&
dquot
->
dq_dqb
,
&
ddquot
);
}
}
++
dqstats_array
[
DQSTATS_READS
]
;
dqstats
.
reads
++
;
return
ret
;
return
ret
;
}
}
...
@@ -686,5 +686,7 @@ static void __exit exit_v2_quota_format(void)
...
@@ -686,5 +686,7 @@ static void __exit exit_v2_quota_format(void)
unregister_quota_format
(
&
v2_quota_format
);
unregister_quota_format
(
&
v2_quota_format
);
}
}
EXPORT_NO_SYMBOLS
;
module_init
(
init_v2_quota_format
);
module_init
(
init_v2_quota_format
);
module_exit
(
exit_v2_quota_format
);
module_exit
(
exit_v2_quota_format
);
include/linux/quota.h
View file @
704a6dfc
...
@@ -184,22 +184,18 @@ extern inline void mark_info_dirty(struct mem_dqinfo *info)
...
@@ -184,22 +184,18 @@ extern inline void mark_info_dirty(struct mem_dqinfo *info)
#define sb_dqopt(sb) (&(sb)->s_dquot)
#define sb_dqopt(sb) (&(sb)->s_dquot)
/*
struct
dqstats
{
* Statistics about disc quota.
int
lookups
;
*/
int
drops
;
enum
{
int
reads
;
DQSTATS_LOOKUPS
,
int
writes
;
DQSTATS_DROPS
,
int
cache_hits
;
DQSTATS_READS
,
int
allocated_dquots
;
DQSTATS_WRITES
,
int
free_dquots
;
DQSTATS_CACHE_HITS
,
int
syncs
;
DQSTATS_ALLOCATED
,
DQSTATS_FREE
,
DQSTATS_SYNCS
,
DQSTATS_SIZE
};
};
extern
__u32
dqstats_array
[
DQSTATS_SIZE
]
;
extern
struct
dqstats
dqstats
;
#define NR_DQHASH 43
/* Just an arbitrary number */
#define NR_DQHASH 43
/* Just an arbitrary number */
...
...
include/linux/quotacompat.h
deleted
100644 → 0
View file @
155aba2e
/*
* Definition of symbols used for backward compatible interface
*/
#ifndef _LINUX_QUOTACOMPAT_
#define _LINUX_QUOTACOMPAT_
#include <linux/types.h>
#include <linux/quota.h>
struct
v1c_mem_dqblk
{
__u32
dqb_bhardlimit
;
/* absolute limit on disk blks alloc */
__u32
dqb_bsoftlimit
;
/* preferred limit on disk blks */
__u32
dqb_curblocks
;
/* current block count */
__u32
dqb_ihardlimit
;
/* maximum # allocated inodes */
__u32
dqb_isoftlimit
;
/* preferred inode limit */
__u32
dqb_curinodes
;
/* current # allocated inodes */
time_t
dqb_btime
;
/* time limit for excessive disk use */
time_t
dqb_itime
;
/* time limit for excessive files */
};
struct
v1c_dqstats
{
__u32
lookups
;
__u32
drops
;
__u32
reads
;
__u32
writes
;
__u32
cache_hits
;
__u32
allocated_dquots
;
__u32
free_dquots
;
__u32
syncs
;
};
struct
v2c_mem_dqblk
{
unsigned
int
dqb_ihardlimit
;
unsigned
int
dqb_isoftlimit
;
unsigned
int
dqb_curinodes
;
unsigned
int
dqb_bhardlimit
;
unsigned
int
dqb_bsoftlimit
;
qsize_t
dqb_curspace
;
__kernel_time_t
dqb_btime
;
__kernel_time_t
dqb_itime
;
};
struct
v2c_mem_dqinfo
{
unsigned
int
dqi_bgrace
;
unsigned
int
dqi_igrace
;
unsigned
int
dqi_flags
;
unsigned
int
dqi_blocks
;
unsigned
int
dqi_free_blk
;
unsigned
int
dqi_free_entry
;
};
struct
v2c_dqstats
{
__u32
lookups
;
__u32
drops
;
__u32
reads
;
__u32
writes
;
__u32
cache_hits
;
__u32
allocated_dquots
;
__u32
free_dquots
;
__u32
syncs
;
__u32
version
;
};
#define Q_COMP_QUOTAON 0x0100
/* enable quotas */
#define Q_COMP_QUOTAOFF 0x0200
/* disable quotas */
#define Q_COMP_SYNC 0x0600
/* sync disk copy of a filesystems quotas */
#define Q_V1_GETQUOTA 0x0300
/* get limits and usage */
#define Q_V1_SETQUOTA 0x0400
/* set limits and usage */
#define Q_V1_SETUSE 0x0500
/* set usage */
#define Q_V1_SETQLIM 0x0700
/* set limits */
#define Q_V1_GETSTATS 0x0800
/* get collected stats */
#define Q_V1_RSQUASH 0x1000
/* set root_squash option */
#define Q_V2_SETQLIM 0x0700
/* set limits */
#define Q_V2_GETINFO 0x0900
/* get info about quotas - graces, flags... */
#define Q_V2_SETINFO 0x0A00
/* set info about quotas */
#define Q_V2_SETGRACE 0x0B00
/* set inode and block grace */
#define Q_V2_SETFLAGS 0x0C00
/* set flags for quota */
#define Q_V2_GETQUOTA 0x0D00
/* get limits and usage */
#define Q_V2_SETQUOTA 0x0E00
/* set limits and usage */
#define Q_V2_SETUSE 0x0F00
/* set usage */
#define Q_V2_GETSTATS 0x1100
/* get collected stats */
#endif
include/linux/sysctl.h
View file @
704a6dfc
...
@@ -544,7 +544,19 @@ enum
...
@@ -544,7 +544,19 @@ enum
FS_LEASES
=
13
,
/* int: leases enabled */
FS_LEASES
=
13
,
/* int: leases enabled */
FS_DIR_NOTIFY
=
14
,
/* int: directory notification enabled */
FS_DIR_NOTIFY
=
14
,
/* int: directory notification enabled */
FS_LEASE_TIME
=
15
,
/* int: maximum time to wait for a lease break */
FS_LEASE_TIME
=
15
,
/* int: maximum time to wait for a lease break */
FS_DQSTATS
=
16
,
/* int: disc quota suage statistics */
FS_DQSTATS
=
16
,
/* disc quota usage statistics */
};
/* /proc/sys/fs/quota/ */
enum
{
FS_DQ_LOOKUPS
=
1
,
FS_DQ_DROPS
=
2
,
FS_DQ_READS
=
3
,
FS_DQ_WRITES
=
4
,
FS_DQ_CACHE_HITS
=
5
,
FS_DQ_ALLOCATED
=
6
,
FS_DQ_FREE
=
7
,
FS_DQ_SYNCS
=
8
,
};
};
/* CTL_DEBUG names: */
/* CTL_DEBUG names: */
...
...
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