* Re: [PATCH v2 03/10] cgroup: net_cls: Protect access to task_cls_classid() when built as module
From: Paul E. McKenney @ 2012-08-28 14:47 UTC (permalink / raw)
To: Daniel Wagner
Cc: Tejun Heo, netdev-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, David S. Miller, Gao feng,
Jamal Hadi Salim, John Fastabend, Li Zefan, Neil Horman
In-Reply-To: <503903BD.6020208-kQCPcA+X3s7YtjvyW6yDsg@public.gmane.org>
On Sat, Aug 25, 2012 at 06:56:29PM +0200, Daniel Wagner wrote:
> On 25.08.2012 01:26, Tejun Heo wrote:
> >On Fri, Aug 24, 2012 at 04:01:37PM +0200, Daniel Wagner wrote:
> >>@@ -306,6 +312,11 @@ static void __exit exit_cgroup_cls(void)
> >> synchronize_rcu();
> >> #endif
> >>
> >>+#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> >>+ static_key_slow_dec(&cgroup_cls_enabled);
> >>+ rcu_barrier();
> >
> >Why is this rcu_barrier() necessary?
>
> I have read the rcubarrier.txt document and I got from that that an
> rcu_barrier() is needed when unloading a module. But maybe I got it
> wrong.
>
> So the idea after disabling the jump lables all pending readers in
> task_cls_classid() have left. THe same thing is done in the old code
> with the dynamic id part. With the difference that synchronize_rcu()
> is used.
FWIW, the rcu_barrier() is needed only if the module uses call_rcu().
In that case it is required to ensure that all the resulting callbacks
execute before the module's .text is freed up.
Thanx, Paul
> >In general, please explain what
> >synchronization is going on when using sync constructs which aren't
> >obvious - e.g. memory barriers, rcu barriers.
>
> Sure, I will keep this in mind.
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes
From: Eric Dumazet @ 2012-08-28 14:49 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev, Patrick McHardy, lvs-devel, Julian Anastasov,
Simon Horman, Pablo Neira Ayuso, Hans Schillstrom, Wensong Zhang,
netfilter-devel
In-Reply-To: <20120828142248.11475.15917.stgit@dragon>
On Tue, 2012-08-28 at 16:23 +0200, Jesper Dangaard Brouer wrote:
> This patch is necessary, to make IPVS work, after Patrick McHardys
> IPv6 NAT defragmentation changes.
>
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
> ---
> In V2: the tunnel mode is no longer a special case.
>
> net/netfilter/ipvs/ip_vs_xmit.c | 9 ++++++++-
> 1 files changed, 8 insertions(+), 1 deletions(-)
>
> diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
> index 67a3978..56f6d5d 100644
> --- a/net/netfilter/ipvs/ip_vs_xmit.c
> +++ b/net/netfilter/ipvs/ip_vs_xmit.c
> @@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
> static inline bool
> __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
> {
> - if (skb->len > mtu && !skb_is_gso(skb)) {
> + if (IP6CB(skb)->frag_max_size) {
> + /* frag_max_size tell us that, this packet have been
> + * defragmented by netfilter IPv6 conntrack module.
> + */
> + if (IP6CB(skb)->frag_max_size > mtu)
> + return true; /* largest fragment violate MTU */
> + }
> + else if (skb->len > mtu && !skb_is_gso(skb)) {
> return true; /* Packet size violate MTU size */
> }
Couldnt you use a single test ?
if (IP6CB(skb)->frag_max_size > mtu)
return true;
if (skb->len > mtu && !skb_is_gso(skb))
return true;
^ permalink raw reply
* Warning in kernel/workqueue.c:1225 worker_enter_idle+0xc7/0x120() when HTB shaper is initialized on top of ifb
From: Andrew @ 2012-08-28 14:26 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: text/plain, Size: 2401 bytes --]
Hi all.
I tested distro with 3.2.28 kernel on Phenom II 955 at MS-7596 mobo, and I saw
next warning:
------------[ cut here ]------------
WARNING: at
/var/testpoint/LEAF-new/source/i486-unknown-linux-uclibc/linux/linux-3.2.28/kernel/workqueue.c:1225
worker_enter_idle+0xc7/0x120()
Hardware name: MS-7596
Modules linked in: ipv6 k10temp sp5100_tco i2c_piix4 i2c_core
snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_pcm snd_timer igb(O) snd
shpchp dca soundcore pci_hotplug snd_page_alloc powernow_k8 freq_table
processor thermal_sys hwmon mperf act_mirred cls_u32 cls_fw sch_ingress
sch_prio sch_sfq sch_htb ifb 8021q softdog pptp gre sha1_generic arc4 ecb
ppp_mppe pppoe pppox ppp_synctty ppp_generic slhc sd_mod pata_atiixp pata_acpi
ahci libahci ata_generic ehci_hcd ohci_hcd libata usbcore scsi_mod usb_common
pcspkr vfat fat isofs
Pid: 325, comm: kworker/1:1 Tainted: G O 3.2.28-i686 #1
Call Trace:
[<81032dc8>] ? warn_slowpath_common+0x78/0xb0
[<810453b7>] ? worker_enter_idle+0xc7/0x120
[<810453b7>] ? worker_enter_idle+0xc7/0x120
[<81032e1b>] ? warn_slowpath_null+0x1b/0x20
[<810453b7>] ? worker_enter_idle+0xc7/0x120
[<81047417>] ? worker_thread+0x1b7/0x2b0
[<81047260>] ? manage_workers.isra.31+0x1c0/0x1c0
[<8104aba9>] ? kthread+0x69/0x70
[<8104ab40>] ? kthread_worker_fn+0x100/0x100
[<8127c47e>] ? kernel_thread_helper+0x6/0xd
---[ end trace ac1da733157f3bc5 ]---
It was caused during shaper initialization (creating HTB hierarchical shaper on
ifb0 device, with hash filter table for 3 /22 networks, 3 classes per IP), and
appears only once, at start of shaper init (shaper init takes ~1 minute).
It is reproducible, PID is almost every time the same (just once it was 62xx and
points, as I remember, to kworker/2:1).
Kernel config, script that initializes shaper and script config is in attach.
System has, among other mentioned hardware, 2x2GB DDR3 RAM, and i82576-based
LAN card that uses igb-3.3.6 driver.
Distro is LEAF (http://leaf.sourceforge.net), development branch from git.
Used gcc version is 4.6.3; binutils - 2.21a or 2.22 (I can't remember which one
is actually used for that build - we switched for 2.22 and back to 2.21 after
errors caused by binutils update, then - again to 2.22).
If needed I can place tarball that was used on this PC (~90MB).
I placed this bug at bugzilla (bug 46501), and received recommendation to ask here.
[-- Attachment #2: hsh.conf --]
[-- Type: text/plain, Size: 400 bytes --]
tc="/sbin/tc"
ip="/sbin/ip"
sed="/bin/sed"
awk="/usr/bin/awk"
POOLS="91.202.132.0/22 91.226.56.0/22 10.251.0.0/22"
UPDEVS="ifb0 vlan1 vlan2"
UPDEVINIT="$ip l s ifb0 up 2>/dev/null"
UPDEVSTOP="$tc q d root dev ifb0 2>/dev/null; $ip l s ifb0 down 2>/dev/null;\
$tc q d root dev vlan1 2>/dev/null; $tc q d root dev vlan2 2>/dev/null"
URATE=1000Mbit
UHRATE=500Mbit
UCEIL=1000Mbit
UBURST="burst 256k"
[-- Attachment #3: hsh.sh --]
[-- Type: text/plain, Size: 5620 bytes --]
#!/bin/sh
. /etc/hsh.conf
#convert ip to integer
ip2int() {
echo $@|$sed 's/\(\.\|\/\)/ /g'|$awk '{if ((NF==4)||(NF==5)) {OFMT = "%.0f";
print $1*2^24+$2*2^16+$3*2^8+$4}}'
}
#convert integer to ip
int2ip() {
echo $@|$awk '{if (NF==1) {s1=$1%2^24; s2=$1%2^16; OFMT = "%.0f";\
print int($1/2^24)"."int(s1/2^16)"."int(s2/2^8)"."$1%256}}'
}
#get subnet addr for ip/mask
subnet() {
echo $@|$sed 's/\(\.\|\/\)/ /g'|$awk '{if (NF==5) {ip=$1*2^24+$2*2^16+$3*2^8+$4; \
subnet=ip-ip%2^(32-$5); s1=subnet%2^24; s2=subnet%2^16; OFMT = "%.0f";\
print int(subnet/2^24)"."int(s1/2^16)"."int(s2/2^8)"."subnet%256"/"$5}}'
}
#get width of subnet
netwidth() {
echo $@|$sed 's/\(\.\|\/\)/ /g'|$awk '{if (NF==5) {OFMT = "%.0f"; print 2^(32-$5)}}'
}
#get # of 256-byte subnets of network
subcnt() {
echo $@|$sed 's/\(\.\|\/\)/ /g'|$awk '{if (NF==5) {width=2^(32-$5); i=(width%256>0);
OFMT = "%.0f"; print int(width/256)+i }}'
}
#return max of 2 ints
max() {
echo $@|$awk '{OFMT = "%.0f"; if (NF==2) {if ($1>$2) {print $1} else {print $2}}}'
}
#print as hex
hex() {
echo $@|$awk '{if (NF==1) {printf "%x", $1}}'
}
#sequence from $1 to $1+$2-1
lseq() {
echo $@|$awk '{OFMT = "%.0f"; if (NF==2) {for (i=0;i<$2;i++) {print $1+i}}}'
}
#init device $1
initdev() {
echo $UPDEVINIT|sh
$tc q d root dev $1 2>/dev/null
$tc q a root dev $1 handle 1: htb default 2
$tc c a dev $1 parent 1: classid 1:1 htb rate $URATE ceil $UCEIL $UBURST prio 1 quantum 1514
$tc c a dev $1 parent 1: classid 1:2 htb rate $URATE ceil $UCEIL $UBURST prio 2 quantum 1514
$tc q a dev $1 parent 1:2 handle 2: sfq perturb 10 quantum 1514
$tc f a dev $1 parent 1: prio 10 protocol ip u32
}
#add rule $1 with addr $2 for table $3 with default speed on device $4
addrule() {
ar_id=$(($POOLWIDTH*($3+1)+$1))
ar_id1=$(($RULECOUNT+$ar_id))
ar_id2=$(($RULECOUNT*2+$ar_id))
ar_h1=$(hex $1)
$tc c a dev $4 parent 1:1 classid 1:$ar_id htb rate $URATE ceil $UCEIL $UBURST prio 1 quantum 1514
$tc c a dev $4 parent 1:$ar_id classid 1:$ar_id1 htb rate $UHRATE ceil $UCEIL $UBURST prio 2 quantum 1514
$tc c a dev $4 parent 1:$ar_id classid 1:$ar_id2 htb rate $UHRATE ceil $UCEIL $UBURST prio 1 quantum 1514
$tc q a dev $4 parent 1:$ar_id1 handle $ar_id1: sfq perturb 10 quantum 1514
$tc q a dev $4 parent 1:$ar_id2 handle $ar_id2: sfq perturb 10 quantum 1514
$tc f a dev $4 parent 1: protocol ip prio 1 u32 ht $3:$ar_h1: \
match ip tos 0x10 0xff flowid 1:$ar_id2
$tc f a dev $4 parent 1: protocol ip prio 2 u32 ht $3:$ar_h1: \
match ip protocol 6 0xff match u8 0x45 0xff at 0 match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 flowid 1:$ar_id2
$tc f a dev $4 parent 1: protocol ip prio 3 u32 ht $3:$ar_h1: \
match ip protocol 1 0xff flowid 1:$ar_id2
$tc f a dev $4 parent 1: protocol ip prio 4 u32 ht $3:$ar_h1: match ip src $2 \
flowid 1:$ar_id1
}
#set speed for rule $1 in table $2 with rate $3 kbit on device $4
setspeed() {
ss_id=$(($POOLWIDTH*($2+1)+$1))
ss_id1=$(($RULECOUNT+$ss_id))
ss_id2=$(($RULECOUNT*2+$ss_id))
ss_hr=$(($3/2))
$tc c r dev $4 parent 1:1 classid 1:$ss_id htb rate ${3}kbit $UBURST prio 1 quantum 1514
$tc c r dev $4 parent 1:$ss_id classid 1:$ss_id1 htb rate ${ss_hr}kbit ceil ${3}kbit $UBURST prio 2 quantum 1514
$tc c r dev $4 parent 1:$ss_id classid 1:$ss_id2 htb rate ${ss_hr}kbit ceil ${3}kbit $UBURST prio 1 quantum 1514
}
#fill table for subnet addr $1, device $2
addtable() {
nwidth=$(netwidth $1)
$tc f a dev $2 parent 1:1 prio 10 handle $tctr: protocol ip u32 divisor $nwidth
$tc f a dev $2 parent 1: protocol ip prio 10 u32 ht 800:: \
match ip src $(subnet $1) \
hashkey mask 0x$(hex $(($nwidth-1))) at 12 \
link $tctr:
at_t=0
for at_i in $(lseq $(ip2int $1) $nwidth); do
addrule $at_t $(int2ip $at_i) $tctr $2
at_t=$(($at_t+1))
done
}
#divide network $1 by subnets
divnet() {
for dn_net in $@; do
dn_count=$(subcnt $dn_net)
if [ $dn_count -gt 1 ]; then
dn_subnet=$(ip2int $(subnet $dn_net))
for dn_i in $(lseq 0 $dn_count); do
echo $(int2ip $((dn_subnet+dn_i*256)))/24
done
else
echo $dn_net
fi
done
}
#is ip $2 in subnet $1?
chkip() {
echo $(ip2int $1) $(ip2int $2) $(netwidth $1)|awk '{print (($2>=$1)&&($2<=$1+$3))}'
}
POOLWIDTH=0
NPOOLS=$(divnet $POOLS)
NETCOUNT=$(echo $NPOOLS|wc -w)
for i in $NPOOLS; do
POOLWIDTH=$(max $POOLWIDTH $(netwidth $i))
done
RULECOUNT=$(($POOLWIDTH*$NETCOUNT))
tctr=1
case "$1" in
init)
for iface in $UPDEVS; do
initdev $iface
tctr=1
for i in $NPOOLS; do
addtable $i $iface
tctr=$(($tctr+1))
done
done;;
set)
for i in $NPOOLS; do
if [ $(chkip $i $2) -eq 1 ]; then
rulenum=$(($(ip2int $2)-$(ip2int $i)))
if [ -z "$4" ]; then
for iface in $UPDEVS; do
setspeed $rulenum $tctr $3 $iface
done
else
setspeed $rulenum $tctr $3 $4
fi
exit 0
fi
tctr=$(($tctr+1))
done
echo "This IP isn't in pool!"
exit 1;;
cstat)
for i in $NPOOLS; do
if [ $(chkip $i $2) -eq 1 ]; then
cl1=$(($POOLWIDTH*($tctr+1)+$(ip2int $2)-$(ip2int $i)))
if [ -z "$3" ]; then
for iface in $UPDEVS; do
echo "===== Interface $iface ====="
$tc -s c s dev $iface|grep -A 4 " 1:$cl1 "
done;
else
$tc -s c s dev $3|grep -A 4 " 1:$cl1 "
fi
exit 0
fi
tctr=$(($tctr+1))
done
echo "This IP isn't in pool!"
exit 1;;
stop)
echo $UPDEVSTOP|sh;;
*)
echo Usage: "$0 (init|stop|set <ip> <speed in kbit> [iface]|cstat <ip> [iface])";;
esac
[-- Attachment #4: Bering-3.2.28.config --]
[-- Type: application/xml, Size: 85157 bytes --]
^ permalink raw reply
* Re: [PATCH v2 03/10] cgroup: net_cls: Protect access to task_cls_classid() when built as module
From: Daniel Wagner @ 2012-08-28 16:41 UTC (permalink / raw)
To: Paul E. McKenney
Cc: Tejun Heo, netdev-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, David S. Miller, Gao feng,
Jamal Hadi Salim, John Fastabend, Li Zefan, Neil Horman
In-Reply-To: <20120828144725.GR2961-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
On Tue, Aug 28, 2012 at 07:47:25AM -0700, Paul E. McKenney wrote:
> On Sat, Aug 25, 2012 at 06:56:29PM +0200, Daniel Wagner wrote:
> > On 25.08.2012 01:26, Tejun Heo wrote:
> > >On Fri, Aug 24, 2012 at 04:01:37PM +0200, Daniel Wagner wrote:
> > >>@@ -306,6 +312,11 @@ static void __exit exit_cgroup_cls(void)
> > >> synchronize_rcu();
> > >> #endif
> > >>
> > >>+#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> > >>+ static_key_slow_dec(&cgroup_cls_enabled);
> > >>+ rcu_barrier();
> > >
> > >Why is this rcu_barrier() necessary?
> >
> > I have read the rcubarrier.txt document and I got from that that an
> > rcu_barrier() is needed when unloading a module. But maybe I got it
> > wrong.
> >
> > So the idea after disabling the jump lables all pending readers in
> > task_cls_classid() have left. THe same thing is done in the old code
> > with the dynamic id part. With the difference that synchronize_rcu()
> > is used.
>
> FWIW, the rcu_barrier() is needed only if the module uses call_rcu().
> In that case it is required to ensure that all the resulting callbacks
> execute before the module's .text is freed up.
Thanks for the clarification. After reading the documentations again
and I think this here should do the trick:
static inline u32 task_cls_classid(struct task_struct *p)
{
struct cgroup_cls_state *cs;
u32 classid = 0;
if (!clscg_enabled || in_interrupt())
return 0;
rcu_read_lock();
cs = container_of(task_subsys_state(p, net_cls_subsys_id),
struct cgroup_cls_state, css);
if (cs)
classid = cs->classid;
rcu_read_unlock();
return classid;
}
static void __exit exit_cgroup_cls(void)
{
unregister_tcf_proto_ops(&cls_cgroup_ops);
#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
static_key_slow_dec(&cgroup_cls_enabled);
synchronize_rcu();
#endif
cgroup_unload_subsys(&net_cls_subsys);
}
So when unloading the module, we first disable the static branch, then
we wait for all old readers leaving the reader side issuing a
synchronize_rcu(). New readers might already have passed the static
branch and now entering the reader side. So we need to test if the
pointer we retrieve is valid. Basically, this change is using the same
approach we had before. Instead looking at the id is valid we look at
the pointer if it is valid.
^ permalink raw reply
* Re: [PATCH] iproute2: tc.8: update UNITS section.
From: Ben Hutchings @ 2012-08-28 16:54 UTC (permalink / raw)
To: Li Wei; +Cc: shemminger, netdev
In-Reply-To: <1346132337-21325-1-git-send-email-lw@cn.fujitsu.com>
On Tue, 2012-08-28 at 13:38 +0800, Li Wei wrote:
> - rename section UNITS to PARAMETERS.
> - break section PARAMETERS down to four subsections to cover the
> common used parameter types(RATES, TIMES, SIZES, VALUES).
> - add some explaination for IEC units in RATES.
> - point out the max value we can set for RATES, TIMES and SIZES.
>
> Signed-off-by: Li Wei <lw@cn.fujitsu.com>
> ---
> man/man8/tc.8 | 111 +++++++++++++++++++++++++++++++++++++++++++--------------
> 1 file changed, 85 insertions(+), 26 deletions(-)
>
> diff --git a/man/man8/tc.8 b/man/man8/tc.8
> index 98fbfcd..44d644a 100644
> --- a/man/man8/tc.8
> +++ b/man/man8/tc.8
> @@ -257,19 +257,20 @@ qdiscs applies.
> FILTERS
> Filters have a three part ID, which is only needed when using a hashed
> filter hierarchy.
> -.SH UNITS
> -All parameters accept a floating point number, possibly followed by a unit.
> -.P
> -Bandwidths or rates can be specified in:
> -.TP
> -bps
> -Bytes per second
> +
> +.SH PARAMETERS
> +These following parameters are widely used in TC, for other parameters,
'These' should be 'The'.
'for other parameters' should begin a new sentence.
> +see the man page for individual qdiscs.
'page' should be 'pages'.
> +
> .TP
> -kbps
> -Kilobytes per second
> +RATES
> +Bandwidths or rates.
> +These parameters accept a floating point number, possibly followed by
> +a unit(both SI and IEC units supported).
Missing space before the open-parenthesis.
> +.RS
> .TP
> -mbps
> -Megabytes per second
> +bit or a bare number
> +Bits per second
> .TP
> kbit
> Kilobits per second
> @@ -277,27 +278,41 @@ Kilobits per second
> mbit
> Megabits per second
> .TP
> -bit or a bare number
> -Bits per second
> -.P
> -Amounts of data can be specified in:
> +gbit
> +Gegabits per second
'Gigabits'
> .TP
> -kb or k
> -Kilobytes
> +tbit
> +Terabits per second
> .TP
> -mb or m
> -Megabytes
> +bps
> +Bytes per second
> .TP
> -mbit
> -Megabits
> +kbps
> +Kilobytes per second
> .TP
> -kbit
> -Kilobits
> +mbps
> +Megabytes per second
> .TP
> -b or a bare number
> -Bytes.
> +gbps
> +Gigabytes per second
> +.TP
> +tbps
> +Terabytes per second
> +
> +.P
> +To specified in IEC units, just replace the SI prefix(k-, m-, g-, t-) with
> +IEC prefix(ki-, mi-, gi- and ti-) respectively.
'specified' should be 'specify'.
The word 'just' is not needed.
Missing spaces before the open-parentheses.
> +
> .P
> -Lengths of time can be specified in:
> +TC store rates as a __u32 integer in bps internally,
> +so we can specify a max rate of UINT32_MAX bps.
> +.RE
> +
> +.TP
> +TIMES
> +Length of time. Can be specified as a float pointing number
'float pointing' should be 'floating point' :-)
> +followed by an optional unit:
> +.RS
> .TP
> s, sec or secs
> Whole seconds
> @@ -308,6 +323,50 @@ Milliseconds
> us, usec, usecs or a bare number
> Microseconds.
>
> +.P
> +TC defined it's own time unit(equals to microsecond) and store time values
'it's' means 'it is'; here it should be 'its'.
'equals' should be 'equal'.
'store' should be 'stores'.
Missing space before the open parenthesis, again.
> +as __u32 integer, thus we can specify a max time value of UINT32_MAX usecs.
I don't think user documentation should use names like '__u32' and
'UINT32_MAX'. Instead it should say '32-bit unsigned integer' and '4294
seconds'.
> +.RE
> +
> +.TP
> +SIZES
> +Amounts of data. Can be specified as a float pointing number
'float pointing' should be 'floating point' again
> +followed by an optional unit:
> +.RS
> +.TP
> +b or a bare number
> +Bytes.
> +.TP
> +kbit
> +Kilobites
'kilobits'
> +.TP
> +kb or k
> +Kilobytes
> +.TP
> +mbit
> +Megabits
> +.TP
> +mb or m
> +Megabytes
> +.TP
> +gbit
> +Gigabites
'gigabits'
> +.TP
> +gb or g
> +Gigabytes
> +
> +.P
> +TC store sizes internally as __u32 integer in byte, so we can specify
> +a max size of UINT32_MAX bytes.
'store' should be 'stores'.
Same issue with the type and maximum names.
> +.RE
> +
> +.TP
> +VALUES
> +Other values without a unit.
> +These parameters read as decimal by default, but you can
'read' should be 'are read' or 'are interpreted'
Ben.
> +indicate TC to read them as octal and hexadecimal by adding a '0'
> +or '0x' prefix respectively.
> +
> .SH TC COMMANDS
> The following commands are available for qdiscs, classes and filter:
> .TP
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* syn connection not replied with ack
From: mpe @ 2012-08-28 17:03 UTC (permalink / raw)
To: netdev
Hi all,
I have very very strange behaviour with a virtual machine (centos 6
up-to-date).
Then I try to connect to it with a linux ssh client, I see the syn, but
not the syn-ack replied. On the same target when I connect with windows
machine, it reply correctly and the communication starts.
tshark show me with linux:
386.134073 172.18.0.160 -> 172.18.0.254 TCP 45092 > ssh [SYN] Seq=0
Win=4240 Len=0 MSS=1060 TSV=497047 TSER=0 WS=5
389.134556 172.18.0.160 -> 172.18.0.254 TCP 45092 > ssh [SYN] Seq=0
Win=4240 Len=0 MSS=1060 TSV=497798 TSER=0 WS=5
395.134926 172.18.0.160 -> 172.18.0.254 TCP 45092 > ssh [SYN] Seq=0
Win=4240 Len=0 MSS=1060 TSV=499298 TSER=0 WS=5
and windows:
1099.091686 172.18.0.141 -> 172.18.0.254 TCP 32906 > ssh [SYN] Seq=0
Win=8192 Len=0 MSS=1260 WS=8
1099.092934 172.18.0.254 -> 172.18.0.141 TCP ssh > 32906 [SYN, ACK]
Seq=0 Ack=1 Win=5840 Len=0 MSS=1380
1099.092960 172.18.0.141 -> 172.18.0.254 TCP 32906 > ssh [ACK] Seq=1
Ack=1 Win=65520 Len=0
1099.102017 172.18.0.254 -> 172.18.0.141 SSH Server Protocol:
SSH-2.0-OpenSSH_4.3
iptables are disabled, no modules active (lsmod | grep ip show nothing)
I tried also to remove the vmware vmxnet3 module, reloaded, network
restart, but the same.
But... if I reboot, the communication start for the next 2/3 days and
after it stops another time.
Hope that someone can help me.
Michele
^ permalink raw reply
* Re: First pass at MSG_FASTOPEN support in top-of-trunk netperf
From: Rick Jones @ 2012-08-28 17:10 UTC (permalink / raw)
To: H.K. Jerry Chu; +Cc: netdev
In-Reply-To: <CAFbMe2MY11VoXbGPDcLzHiHBzskoQk6eL1S9VWV5Vd1u0aRjNw@mail.gmail.com>
>> There was a ~25% increase in TCP_CRR performance, even without the server
>> actually accepting the magic TCP option. Is that actually expected?
>
> I have a locally enhanced netperf for TCP_CRR over Fast Open and I've
> noticed the numbers can change drastically between runs. I have not got
> the time to investigate why. (Does it have to do with scheduler and CPU
> locality?) How consistent is your perf number?
I recall the performance being reasonably consistent but there has been
a vacation of my own in the middle there so my dimm memory is a bit fuzzy :)
Historically (and going beyond just Linux) a TCP_CRR test can have some
non-trivial run to run variation thanks to (attempted) TIME_WAIT reuse.
Whether that is happening to you I don't know, but it might be worth a
look.
> I plan to submit the server side code soon and will work with you to add
> the server side support to TCP_CRR (it requires a new TCP_FASTOPEN
> socket option to enable Fast Open on a listener.)
Works for me.
happy benchmarking,
rick jones
^ permalink raw reply
* Re: [PATCH] userns: Add basic quota support v2
From: Eric W. Biederman @ 2012-08-28 17:34 UTC (permalink / raw)
To: Jan Kara
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das
In-Reply-To: <20120828090544.GC5146@quack.suse.cz>
Jan Kara <jack@suse.cz> writes:
> On Mon 27-08-12 17:12:16, Eric W. Biederman wrote:
>> Add the data type struct qown which holds the owning identifier of a
>> quota. struct qown is a replacement for the implicit union of uid,
>> gid and project stored in an unsigned int and the quota type field
>> that is was used in the quota data structures. Making the data type
>> explicit allows the kuid_t and kgid_t type safety to propogate more
>> thoroughly through the code, revealing more places where uid/gid
>> conversions need be made.
>>
>> Allong with the data type struct qown comes the helper functions
> ^^^^ Along
>
>> qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
>> make_qown_invalid, make_qown_uid, make_qown_gid.
>>
>> Replace struct dquot dq_id and dq_type with dq_own a struct qown.
>>
>> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
>> and dquot_set_dqblk to use struct qown.
>>
>> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
>> the change in quota structures and signatures. The ocfs2 changes are
>> larger than most because of the extensive tracing throughout the ocfs2
>> quota code that prints out dq_id.
>>
>> v2:
>> - Renamed qown_t struct qown
>> - Added the quota type to struct qown.
>> - Removed enum quota_type (In this patch it was just noise)
>> - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
>> - Taught qown to handle xfs project ids (but only in init_user_ns).
>> Q_XGETQUOTA calls .get_quotblk with project ids.
> Just a couple one minor comments below...
>
>> @@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>> static int quota_getquota(struct super_block *sb, int type, qid_t id,
>> void __user *addr)
>> {
>> + struct qown qown;
>> struct fs_disk_quota fdq;
>> struct if_dqblk idq;
>> int ret;
>>
>> if (!sb->s_qcop->get_dqblk)
>> return -ENOSYS;
>> - ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
>> + qown = make_qown(current_user_ns(), type, id);
>> + if (qown_valid(qown))
> ^ missing '!'
Good catch thank you.
>> + return -EINVAL;
>> + ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
>> if (ret)
>> return ret;
>> copy_to_if_dqblk(&idq, &fdq);
> ...
>> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
>> +{
>> + switch (qown.type) {
>> + case USRQUOTA:
>> + return from_kuid(user_ns, qown.uid);
>> + case GRPQUOTA:
>> + return from_kgid(user_ns, qown.gid);
>> + case XQM_PRJQUOTA:
>> + return (user_ns == &init_user_ns) ? qown.prj : -1;
>> + default:
>> + BUG();
>> + }
>> +}
> I would like a bit more if the function somehow expressed in its name
> that it returns id. id_from_qown() might be a bit too long given how often
> it is used. qown2id() would be OK but it would be inconsistent with how
> names of other functions you've added are formed. So I'm somewhat
> undecided...
The qown vs id distinction bothers me a little bit.
I almost want to name it struct kid, and the functions make_kid,
from_kid etc. Where the emphasis is that we are transforming in and out
of the kernel internal form. I don't really like make_kid because id as
a base name seems to generic and it barely tells you it is. Perhaps
make_kqid. Where we call the quota ids and qid for short?
I am a little uncomfortable calling them kqids because the userspace
code also places format_ids in a plain qid_t. But make_kqid and
from_kqid seems the best alternate set of names I can come up with.
Eric
^ permalink raw reply
* Re: [PATCH] userns: Add basic quota support v2
From: Jan Kara @ 2012-08-28 17:51 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das
In-Reply-To: <87a9xe7wfn.fsf@xmission.com>
On Tue 28-08-12 10:34:04, Eric W. Biederman wrote:
> Jan Kara <jack@suse.cz> writes:
> >> + return -EINVAL;
> >> + ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
> >> if (ret)
> >> return ret;
> >> copy_to_if_dqblk(&idq, &fdq);
> > ...
> >> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
> >> +{
> >> + switch (qown.type) {
> >> + case USRQUOTA:
> >> + return from_kuid(user_ns, qown.uid);
> >> + case GRPQUOTA:
> >> + return from_kgid(user_ns, qown.gid);
> >> + case XQM_PRJQUOTA:
> >> + return (user_ns == &init_user_ns) ? qown.prj : -1;
> >> + default:
> >> + BUG();
> >> + }
> >> +}
> > I would like a bit more if the function somehow expressed in its name
> > that it returns id. id_from_qown() might be a bit too long given how often
> > it is used. qown2id() would be OK but it would be inconsistent with how
> > names of other functions you've added are formed. So I'm somewhat
> > undecided...
>
> The qown vs id distinction bothers me a little bit.
>
> I almost want to name it struct kid, and the functions make_kid,
> from_kid etc. Where the emphasis is that we are transforming in and out
> of the kernel internal form. I don't really like make_kid because id as
> a base name seems to generic and it barely tells you it is. Perhaps
> make_kqid. Where we call the quota ids and qid for short?
>
> I am a little uncomfortable calling them kqids because the userspace
> code also places format_ids in a plain qid_t. But make_kqid and
> from_kqid seems the best alternate set of names I can come up with.
OK, these would seem reasonable to me.
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply
* [PATCH] userns: Add basic quota support v3
From: Eric W. Biederman @ 2012-08-28 17:36 UTC (permalink / raw)
To: Jan Kara
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das
In-Reply-To: <87a9xe7wfn.fsf@xmission.com>
Add the data type struct qown which holds the owning identifier of a
quota. struct qown is a replacement for the implicit union of uid,
gid and project stored in an unsigned int and the quota type field
that is was used in the quota data structures. Making the data type
explicit allows the kuid_t and kgid_t type safety to propogate more
thoroughly through the code, revealing more places where uid/gid
conversions need be made.
Along with the data type struct qown comes the helper functions
qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
make_qown_invalid, make_qown_uid, make_qown_gid.
Replace struct dquot dq_id and dq_type with dq_own a struct qown.
Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
and dquot_set_dqblk to use struct qown.
Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
the change in quota structures and signatures. The ocfs2 changes are
larger than most because of the extensive tracing throughout the ocfs2
quota code that prints out dq_id.
v3:
- Add missing negation on qown_valid
v2:
- Renamed qown_t struct qown
- Added the quota type to struct qown.
- Removed enum quota_type (In this patch it was just noise)
- Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
- Taught qown to handle xfs project ids (but only in init_user_ns).
Q_XGETQUOTA calls .get_quotblk with project ids.
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Ben Myers <bpm@sgi.com>
Cc: Alex Elder <elder@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
fs/ext3/super.c | 2 +-
fs/ext4/super.c | 2 +-
fs/gfs2/quota.c | 52 +++++++++------
fs/ocfs2/file.c | 6 +-
fs/ocfs2/quota_global.c | 43 +++++++-----
fs/ocfs2/quota_local.c | 15 +++--
fs/quota/dquot.c | 118 +++++++++++++++++-----------------
fs/quota/netlink.c | 10 ++-
fs/quota/quota.c | 28 ++++++--
fs/quota/quota_tree.c | 35 ++++++----
fs/quota/quota_v1.c | 12 ++--
fs/quota/quota_v2.c | 26 ++++---
fs/xfs/xfs_quotaops.c | 14 ++--
fs/xfs/xfs_trans_dquot.c | 8 ++-
include/linux/quota.h | 162 ++++++++++++++++++++++++++++++++++++++++++++--
include/linux/quotaops.h | 6 +-
init/Kconfig | 2 -
17 files changed, 371 insertions(+), 170 deletions(-)
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..c5879f1 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2814,7 +2814,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
static inline struct inode *dquot_to_inode(struct dquot *dquot)
{
- return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
}
static int ext3_write_dquot(struct dquot *dquot)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..f60b48f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4796,7 +4796,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
static inline struct inode *dquot_to_inode(struct dquot *dquot)
{
- return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
}
static int ext4_write_dquot(struct dquot *dquot)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..f0310f9 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
return 0;
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+ int qtype;
+ struct qown qown;
qd = ip->i_res->rs_qa_qd[x];
if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
@@ -1068,11 +1070,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
value += qd->qd_change;
spin_unlock(&qd_lru_lock);
+ qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
+ qown = make_qown(&init_user_ns, qtype, qd->qd_id);
if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
print_message(qd, "exceeded");
- quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
- USRQUOTA : GRPQUOTA, qd->qd_id,
- sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+ quota_send_warning(qown, sdp->sd_vfs->s_dev,
+ QUOTA_NL_BHARDWARN);
error = -EDQUOT;
break;
@@ -1081,9 +1084,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
time_after_eq(jiffies, qd->qd_last_warn +
gfs2_tune_get(sdp,
gt_quota_warn_period) * HZ)) {
- quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
- USRQUOTA : GRPQUOTA, qd->qd_id,
- sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
+ quota_send_warning(qown, sdp->sd_vfs->s_dev,
+ QUOTA_NL_BSOFTWARN);
error = print_message(qd, "warning");
qd->qd_last_warn = jiffies;
}
@@ -1469,7 +1471,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
return 0;
}
-static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
+static int gfs2_get_dqblk(struct super_block *sb, struct qown qown,
struct fs_disk_quota *fdq)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
@@ -1477,20 +1479,24 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
struct gfs2_quota_data *qd;
struct gfs2_holder q_gh;
int error;
+ int user;
+ u32 gfs_id;
memset(fdq, 0, sizeof(struct fs_disk_quota));
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return -ESRCH; /* Crazy XFS error code */
- if (type == USRQUOTA)
- type = QUOTA_USER;
- else if (type == GRPQUOTA)
- type = QUOTA_GROUP;
+ gfs_id = from_qown(&init_user_ns, qown);
+
+ if (qown.type == USRQUOTA)
+ user = QUOTA_USER;
+ else if (qown.type == GRPQUOTA)
+ user = QUOTA_GROUP;
else
return -EINVAL;
- error = qd_get(sdp, type, id, &qd);
+ error = qd_get(sdp, user, gfs_id, &qd);
if (error)
return error;
error = do_glock(qd, FORCE, &q_gh);
@@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
fdq->d_version = FS_DQUOT_VERSION;
- fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
- fdq->d_id = id;
+ fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+ fdq->d_id = gfs_id;
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
@@ -1514,8 +1520,8 @@ out:
/* GFS2 only supports a subset of the XFS fields */
#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
-static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
- struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb,
+ struct qown qown, struct fs_disk_quota *fdq)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
int alloc_required;
loff_t offset;
int error;
+ int user;
+ u32 gfs_id;
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return -ESRCH; /* Crazy XFS error code */
- switch(type) {
+ gfs_id = from_qown(&init_user_ns, qown);
+
+ switch(qown.type) {
case USRQUOTA:
- type = QUOTA_USER;
+ user = QUOTA_USER;
if (fdq->d_flags != FS_USER_QUOTA)
return -EINVAL;
break;
case GRPQUOTA:
- type = QUOTA_GROUP;
+ user = QUOTA_GROUP;
if (fdq->d_flags != FS_GROUP_QUOTA)
return -EINVAL;
break;
@@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
return -EINVAL;
- if (fdq->d_id != id)
+ if (fdq->d_id != gfs_id)
return -EINVAL;
- error = qd_get(sdp, type, id, &qd);
+ error = qd_get(sdp, user, gfs_id, &qd);
if (error)
return error;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 46a1f6d..3879186 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
- transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
- USRQUOTA);
+ transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(attr->ia_uid));
if (!transfer_to[USRQUOTA]) {
status = -ESRCH;
goto bail_unlock;
@@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
- transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
- GRPQUOTA);
+ transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(attr->ia_gid));
if (!transfer_to[GRPQUOTA]) {
status = -ESRCH;
goto bail_unlock;
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index 0a86e30..dcee469 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -95,7 +95,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
struct ocfs2_global_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -112,11 +112,14 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
{
struct ocfs2_global_disk_dqblk *d = dp;
struct ocfs2_mem_dqinfo *oinfo =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+ struct qown qown;
if (qtree_entry_unused(&oinfo->dqi_gi, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+
+ qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+ return qown_eq(qown, dquot->dq_own);
}
struct qtree_fmt_operations ocfs2_global_ops = {
@@ -475,7 +478,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
{
int err, err2;
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
struct ocfs2_global_disk_dqblk dqblk;
s64 spacechange, inodechange;
@@ -504,7 +507,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
olditime = dquot->dq_dqb.dqb_itime;
oldbtime = dquot->dq_dqb.dqb_btime;
ocfs2_global_disk2memdqb(dquot, &dqblk);
- trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
+ trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_own),
+ dquot->dq_dqb.dqb_curspace,
(long long)spacechange,
dquot->dq_dqb.dqb_curinodes,
(long long)inodechange);
@@ -555,8 +559,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
err = ocfs2_qinfo_lock(info, freeing);
if (err < 0) {
mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
- " (type=%d, id=%u)\n", dquot->dq_type,
- (unsigned)dquot->dq_id);
+ " (type=%d, id=%u)\n", dquot->dq_own.type,
+ (unsigned)from_qown(&init_user_ns, dquot->dq_own));
goto out;
}
if (freeing)
@@ -591,9 +595,10 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
struct ocfs2_super *osb = OCFS2_SB(sb);
int status = 0;
- trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
+ trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_own),
+ dquot->dq_own.type,
type, sb->s_id);
- if (type != dquot->dq_type)
+ if (type != dquot->dq_own.type)
goto out;
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0)
@@ -643,7 +648,8 @@ static int ocfs2_write_dquot(struct dquot *dquot)
struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
int status = 0;
- trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
+ trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_own),
+ dquot->dq_own.type);
handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
if (IS_ERR(handle)) {
@@ -677,11 +683,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
{
handle_t *handle;
struct ocfs2_mem_dqinfo *oinfo =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
int status = 0;
- trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
+ trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_own),
+ dquot->dq_own.type);
mutex_lock(&dquot->dq_lock);
/* Check whether we are not racing with some other dqget() */
@@ -691,7 +698,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
if (status < 0)
goto out;
handle = ocfs2_start_trans(osb,
- ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
+ ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_own.type));
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
@@ -733,13 +740,14 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
int ex = 0;
struct super_block *sb = dquot->dq_sb;
struct ocfs2_super *osb = OCFS2_SB(sb);
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
struct inode *gqinode = info->dqi_gqinode;
int need_alloc = ocfs2_global_qinit_alloc(sb, type);
handle_t *handle;
- trace_ocfs2_acquire_dquot(dquot->dq_id, type);
+ trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, dquot->dq_own),
+ type);
mutex_lock(&dquot->dq_lock);
/*
* We need an exclusive lock, because we're going to update use count
@@ -821,12 +829,13 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
int sync = 0;
int status;
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
handle_t *handle;
struct ocfs2_super *osb = OCFS2_SB(sb);
- trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
+ trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, dquot->dq_own),
+ type);
/* In case user set some limits, sync dquot immediately to global
* quota file so that information propagates quicker */
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index f100bf7..3aec405 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -501,7 +501,9 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
}
dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
ol_dqblk_block_off(sb, chunk, bit));
- dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
+ dquot = dqget(sb,
+ make_qown(&init_user_ns, type,
+ le64_to_cpu(dqblk->dqb_id)));
if (!dquot) {
status = -EIO;
mlog(ML_ERROR, "Failed to get quota structure "
@@ -881,7 +883,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
+ ol_dqblk_block_offset(sb, od->dq_local_off));
- dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
+ dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
+ od->dq_dquot.dq_own));
spin_lock(&dq_data_lock);
dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
od->dq_origspace);
@@ -891,7 +894,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
trace_olq_set_dquot(
(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
- od->dq_dquot.dq_id);
+ from_qown(&init_user_ns, od->dq_dquot.dq_own));
}
/* Write dquot to local quota file */
@@ -900,7 +903,7 @@ int ocfs2_local_write_dquot(struct dquot *dquot)
struct super_block *sb = dquot->dq_sb;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
struct buffer_head *bh;
- struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_type];
+ struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_own.type];
int status;
status = ocfs2_read_quota_phys_block(lqinode, od->dq_local_phys_blk,
@@ -1221,7 +1224,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
int ocfs2_create_local_dquot(struct dquot *dquot)
{
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct inode *lqinode = sb_dqopt(sb)->files[type];
struct ocfs2_quota_chunk *chunk;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1275,7 +1278,7 @@ out:
int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
{
int status;
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
struct super_block *sb = dquot->dq_sb;
struct ocfs2_local_disk_chunk *dchunk;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 36a29b7..766ab61 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -253,11 +253,13 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
static void __dquot_initialize(struct inode *inode, int type);
static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct qown qown)
{
+ unsigned int id;
unsigned long tmp;
- tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+ id = from_qown(&init_user_ns, qown);
+ tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - qown.type);
return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
}
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
static inline void insert_dquot_hash(struct dquot *dquot)
{
struct hlist_head *head;
- head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+ head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_own);
hlist_add_head(&dquot->dq_hash, head);
}
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
}
static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
- unsigned int id, int type)
+ struct qown own)
{
struct hlist_node *node;
struct dquot *dquot;
hlist_for_each (node, dquot_hash+hashent) {
dquot = hlist_entry(node, struct dquot, dq_hash);
- if (dquot->dq_sb == sb && dquot->dq_id == id &&
- dquot->dq_type == type)
+ if (dquot->dq_sb == sb && qown_eq(dquot->dq_own, own))
return dquot;
}
return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
spin_lock(&dq_list_lock);
if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
- info[dquot->dq_type].dqi_dirty_list);
+ info[dquot->dq_own.type].dqi_dirty_list);
ret = 0;
}
spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
mutex_lock(&dquot->dq_lock);
mutex_lock(&dqopt->dqio_mutex);
if (!test_bit(DQ_READ_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_own.type]->read_dqblk(dquot);
if (ret < 0)
goto out_iolock;
set_bit(DQ_READ_B, &dquot->dq_flags);
/* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
/* Write the info if needed */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+ ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_own.type);
}
if (ret < 0)
goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
/* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
else
ret = -EIO;
out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
if (atomic_read(&dquot->dq_count) > 1)
goto out_dqlock;
mutex_lock(&dqopt->dqio_mutex);
- if (dqopt->ops[dquot->dq_type]->release_dqblk) {
- ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+ if (dqopt->ops[dquot->dq_own.type]->release_dqblk) {
+ ret = dqopt->ops[dquot->dq_own.type]->release_dqblk(dquot);
/* Write the info */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+ ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_own.type);
}
if (ret >= 0)
ret = ret2;
@@ -521,7 +522,7 @@ restart:
list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
if (dquot->dq_sb != sb)
continue;
- if (dquot->dq_type != type)
+ if (dquot->dq_own.type != type)
continue;
/* Wait for dquot users */
if (atomic_read(&dquot->dq_count)) {
@@ -741,7 +742,8 @@ void dqput(struct dquot *dquot)
#ifdef CONFIG_QUOTA_DEBUG
if (!atomic_read(&dquot->dq_count)) {
quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
- quotatypes[dquot->dq_type], dquot->dq_id);
+ quotatypes[dquot->dq_own.type],
+ from_qown(&init_user_ns, dquot->dq_own));
BUG();
}
#endif
@@ -752,7 +754,7 @@ we_slept:
/* We have more than one user... nothing to do */
atomic_dec(&dquot->dq_count);
/* Releasing dquot during quotaoff phase? */
- if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+ if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_own.type) &&
atomic_read(&dquot->dq_count) == 1)
wake_up(&dquot->dq_wait_unused);
spin_unlock(&dq_list_lock);
@@ -815,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
INIT_LIST_HEAD(&dquot->dq_dirty);
init_waitqueue_head(&dquot->dq_wait_unused);
dquot->dq_sb = sb;
- dquot->dq_type = type;
+ dquot->dq_own = make_qown_invalid(type);
atomic_set(&dquot->dq_count, 1);
return dquot;
@@ -829,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
* a) checking for quota flags under dq_list_lock and
* b) getting a reference to dquot before we release dq_list_lock
*/
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct qown qown)
{
- unsigned int hashent = hashfn(sb, id, type);
+ unsigned int hashent = hashfn(sb, qown);
struct dquot *dquot = NULL, *empty = NULL;
- if (!sb_has_quota_active(sb, type))
+ if (!sb_has_quota_active(sb, qown.type))
return NULL;
we_slept:
spin_lock(&dq_list_lock);
spin_lock(&dq_state_lock);
- if (!sb_has_quota_active(sb, type)) {
+ if (!sb_has_quota_active(sb, qown.type)) {
spin_unlock(&dq_state_lock);
spin_unlock(&dq_list_lock);
goto out;
}
spin_unlock(&dq_state_lock);
- dquot = find_dquot(hashent, sb, id, type);
+ dquot = find_dquot(hashent, sb, qown);
if (!dquot) {
if (!empty) {
spin_unlock(&dq_list_lock);
- empty = get_empty_dquot(sb, type);
+ empty = get_empty_dquot(sb, qown.type);
if (!empty)
schedule(); /* Try to wait for a moment... */
goto we_slept;
}
dquot = empty;
empty = NULL;
- dquot->dq_id = id;
+ dquot->dq_own = qown;
/* all dquots go on the inuse_list */
put_inuse(dquot);
/* hash it first so it can be found */
@@ -1129,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
struct dquot_warn {
struct super_block *w_sb;
- qid_t w_dq_id;
- short w_dq_type;
+ struct qown w_dq_own;
short w_type;
};
@@ -1154,11 +1155,11 @@ static int need_print_warning(struct dquot_warn *warn)
if (!flag_print_warnings)
return 0;
- switch (warn->w_dq_type) {
+ switch (warn->w_dq_own.type) {
case USRQUOTA:
- return current_fsuid() == warn->w_dq_id;
+ return uid_eq(current_fsuid(), warn->w_dq_own.uid);
case GRPQUOTA:
- return in_group_p(warn->w_dq_id);
+ return in_group_p(warn->w_dq_own.gid);
}
return 0;
}
@@ -1184,7 +1185,7 @@ static void print_warning(struct dquot_warn *warn)
tty_write_message(tty, ": warning, ");
else
tty_write_message(tty, ": write failed, ");
- tty_write_message(tty, quotatypes[warn->w_dq_type]);
+ tty_write_message(tty, quotatypes[warn->w_dq_own.type]);
switch (warntype) {
case QUOTA_NL_IHARDWARN:
msg = " file limit reached.\r\n";
@@ -1217,8 +1218,7 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
return;
warn->w_type = warntype;
warn->w_sb = dquot->dq_sb;
- warn->w_dq_id = dquot->dq_id;
- warn->w_dq_type = dquot->dq_type;
+ warn->w_dq_own = dquot->dq_own;
}
/*
@@ -1236,14 +1236,14 @@ static void flush_warnings(struct dquot_warn *warn)
#ifdef CONFIG_PRINT_QUOTA_WARNING
print_warning(&warn[i]);
#endif
- quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+ quota_send_warning(warn[i].w_dq_own,
warn[i].w_sb->s_dev, warn[i].w_type);
}
}
static int ignore_hardlimit(struct dquot *dquot)
{
- struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
return capable(CAP_SYS_RESOURCE) &&
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1256,7 +1256,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
{
qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
- if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1281,7 +1281,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
dquot->dq_dqb.dqb_itime == 0) {
prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
dquot->dq_dqb.dqb_itime = get_seconds() +
- sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type].dqi_igrace;
}
return 0;
@@ -1294,7 +1294,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
qsize_t tspace;
struct super_block *sb = dquot->dq_sb;
- if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(sb, dquot->dq_own.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1325,7 +1325,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
if (!prealloc) {
prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
dquot->dq_dqb.dqb_btime = get_seconds() +
- sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+ sb_dqopt(sb)->info[dquot->dq_own.type].dqi_bgrace;
}
else
/*
@@ -1344,7 +1344,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
- !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+ !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type))
return QUOTA_NL_NOWARN;
newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1390,7 +1390,6 @@ static int dquot_active(const struct inode *inode)
*/
static void __dquot_initialize(struct inode *inode, int type)
{
- unsigned int id = 0;
int cnt;
struct dquot *got[MAXQUOTAS];
struct super_block *sb = inode->i_sb;
@@ -1403,18 +1402,19 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First get references to structures we might need. */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct qown qown;
got[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
switch (cnt) {
case USRQUOTA:
- id = inode->i_uid;
+ qown = make_qown_uid(inode->i_uid);
break;
case GRPQUOTA:
- id = inode->i_gid;
+ qown = make_qown_gid(inode->i_gid);
break;
}
- got[cnt] = dqget(sb, id, cnt);
+ got[cnt] = dqget(sb, qown);
}
down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1897,10 +1897,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
if (!dquot_active(inode))
return 0;
- if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
- transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
- if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
- transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+ if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+ transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(iattr->ia_uid));
+ if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+ transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(iattr->ia_gid));
ret = __dquot_transfer(inode, transfer_to);
dqput_all(transfer_to);
@@ -2360,9 +2360,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
- di->d_flags = dquot->dq_type == USRQUOTA ?
+ di->d_flags = dquot->dq_own.type == USRQUOTA ?
FS_USER_QUOTA : FS_GROUP_QUOTA;
- di->d_id = dquot->dq_id;
+ di->d_id = from_qown_munged(current_user_ns(), dquot->dq_own);
spin_lock(&dq_data_lock);
di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2376,12 +2376,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
spin_unlock(&dq_data_lock);
}
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown qown,
struct fs_disk_quota *di)
{
struct dquot *dquot;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qown);
if (!dquot)
return -ESRCH;
do_get_dqblk(dquot, di);
@@ -2401,7 +2401,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
- struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
return -EINVAL;
@@ -2488,13 +2488,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
return 0;
}
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown qown,
struct fs_disk_quota *di)
{
struct dquot *dquot;
int rc;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qown);
if (!dquot) {
rc = -ESRCH;
goto out;
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index d67908b..82e99d7 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
*
*/
-void quota_send_warning(short type, unsigned int id, dev_t dev,
+void quota_send_warning(struct qown qown, dev_t dev,
const char warntype)
{
static atomic_t seq;
@@ -56,10 +56,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
"VFS: Cannot store netlink header in quota warning.\n");
goto err_out;
}
- ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+ ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qown.type);
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+ ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
+ from_qown_munged(&init_user_ns, qown));
if (ret)
goto attr_err_out;
ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
@@ -71,7 +72,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+ ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
+ from_kuid_munged(&init_user_ns, current_uid()));
if (ret)
goto attr_err_out;
genlmsg_end(skb, msg_head);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..a31dc42 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
/* allow to query information for dquots we "own" */
case Q_GETQUOTA:
case Q_XGETQUOTA:
- if ((type == USRQUOTA && current_euid() == id) ||
- (type == GRPQUOTA && in_egroup_p(id)))
+ if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
+ (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
break;
/*FALLTHROUGH*/
default:
@@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
static int quota_getquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
+ struct qown qown;
struct fs_disk_quota fdq;
struct if_dqblk idq;
int ret;
if (!sb->s_qcop->get_dqblk)
return -ENOSYS;
- ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+ qown = make_qown(current_user_ns(), type, id);
+ if (!qown_valid(qown))
+ return -EINVAL;
+ ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
if (ret)
return ret;
copy_to_if_dqblk(&idq, &fdq);
@@ -176,13 +180,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
{
struct fs_disk_quota fdq;
struct if_dqblk idq;
+ struct qown qown;
if (copy_from_user(&idq, addr, sizeof(idq)))
return -EFAULT;
if (!sb->s_qcop->set_dqblk)
return -ENOSYS;
+ qown = make_qown(current_user_ns(), type, id);
+ if (!qown_valid(qown))
+ return -EINVAL;
copy_from_if_dqblk(&fdq, &idq);
- return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+ return sb->s_qcop->set_dqblk(sb, qown, &fdq);
}
static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -213,23 +221,31 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
struct fs_disk_quota fdq;
+ struct qown qown;
if (copy_from_user(&fdq, addr, sizeof(fdq)))
return -EFAULT;
if (!sb->s_qcop->set_dqblk)
return -ENOSYS;
- return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+ qown = make_qown(current_user_ns(), type, id);
+ if (!qown_valid(qown))
+ return -EINVAL;
+ return sb->s_qcop->set_dqblk(sb, qown, &fdq);
}
static int quota_getxquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
struct fs_disk_quota fdq;
+ struct qown qown;
int ret;
if (!sb->s_qcop->get_dqblk)
return -ENOSYS;
- ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+ qown = make_qown(current_user_ns(), type, id);
+ if (!qown_valid(qown))
+ return -EINVAL;
+ ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
return -EFAULT;
return ret;
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index e41c1becf..fa48156 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
#define __QUOTA_QT_PARANOIA
-static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
+static int get_index(struct qtree_mem_dqinfo *info, struct qown qown, int depth)
{
unsigned int epb = info->dqi_usable_bs >> 2;
+ qid_t id;
+ id = from_qown(&init_user_ns, qown);
depth = info->dqi_qtree_depth - depth - 1;
while (depth--)
id /= epb;
@@ -244,7 +246,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
/* This is enough as the block is already zeroed and the entry
* list is empty... */
info->dqi_free_entry = blk;
- mark_info_dirty(dquot->dq_sb, dquot->dq_type);
+ mark_info_dirty(dquot->dq_sb, dquot->dq_own.type);
}
/* Block will be full? */
if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
@@ -313,7 +315,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
}
}
ref = (__le32 *)buf;
- newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+ newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
if (!newblk)
newson = 1;
if (depth == info->dqi_qtree_depth - 1) {
@@ -322,7 +324,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
quota_error(dquot->dq_sb, "Inserting already present "
"quota entry (block %u)",
le32_to_cpu(ref[get_index(info,
- dquot->dq_id, depth)]));
+ dquot->dq_own, depth)]));
ret = -EIO;
goto out_buf;
}
@@ -332,7 +334,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
ret = do_insert_tree(info, dquot, &newblk, depth+1);
}
if (newson && ret >= 0) {
- ref[get_index(info, dquot->dq_id, depth)] =
+ ref[get_index(info, dquot->dq_own, depth)] =
cpu_to_le32(newblk);
ret = write_blk(info, *treeblk, buf);
} else if (newact && ret < 0) {
@@ -357,7 +359,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
*/
int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct super_block *sb = dquot->dq_sb;
ssize_t ret;
char *ddquot = getdqbuf(info->dqi_entry_size);
@@ -472,7 +474,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
*blk);
goto out_buf;
}
- newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+ newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
if (depth == info->dqi_qtree_depth - 1) {
ret = free_dqentry(info, dquot, newblk);
newblk = 0;
@@ -481,7 +483,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
}
if (ret >= 0 && !newblk) {
int i;
- ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
+ ref[get_index(info, dquot->dq_own, depth)] = cpu_to_le32(0);
/* Block got empty? */
for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
;
@@ -538,8 +540,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
ddquot += info->dqi_entry_size;
}
if (i == qtree_dqstr_in_blk(info)) {
- quota_error(dquot->dq_sb, "Quota for id %u referenced "
- "but not present", dquot->dq_id);
+ quota_error(dquot->dq_sb,
+ "Quota for id %u referenced but not present",
+ from_qown(&init_user_ns, dquot->dq_own));
ret = -EIO;
goto out_buf;
} else {
@@ -568,7 +571,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
goto out_buf;
}
ret = 0;
- blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+ blk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
if (!blk) /* No reference? */
goto out_buf;
if (depth < info->dqi_qtree_depth - 1)
@@ -589,7 +592,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct super_block *sb = dquot->dq_sb;
loff_t offset;
char *ddquot;
@@ -607,8 +610,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
offset = find_dqentry(info, dquot);
if (offset <= 0) { /* Entry not present? */
if (offset < 0)
- quota_error(sb, "Can't read quota structure "
- "for id %u", dquot->dq_id);
+ quota_error(sb,"Can't read quota structure "
+ "for id %u",
+ from_qown(&init_user_ns,
+ dquot->dq_own));
dquot->dq_off = 0;
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -626,7 +631,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
if (ret >= 0)
ret = -EIO;
quota_error(sb, "Error while reading quota structure for id %u",
- dquot->dq_id);
+ from_qown(&init_user_ns, dquot->dq_own));
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
kfree(ddquot);
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 34b37a6..ec37d70 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
static int v1_read_dqblk(struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_own.type;
struct v1_disk_dqblk dqblk;
if (!sb_dqopt(dquot->dq_sb)->files[type])
@@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
/* Set structure to 0s in case read fails/is after end of file */
memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
- sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
+ sizeof(struct v1_disk_dqblk),
+ v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)
static int v1_commit_dqblk(struct dquot *dquot)
{
- short type = dquot->dq_type;
+ short type = dquot->dq_own.type;
ssize_t ret;
struct v1_disk_dqblk dqblk;
v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
- if (dquot->dq_id == 0) {
+ if (((type == USRQUOTA) && uid_eq(dquot->dq_own.uid, GLOBAL_ROOT_UID)) ||
+ ((type == GRPQUOTA) && gid_eq(dquot->dq_own.gid, GLOBAL_ROOT_GID))) {
dqblk.dqb_btime =
sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
dqblk.dqb_itime =
@@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
if (sb_dqopt(dquot->dq_sb)->files[type])
ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
(char *)&dqblk, sizeof(struct v1_disk_dqblk),
- v1_dqoff(dquot->dq_id));
+ v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
if (ret != sizeof(struct v1_disk_dqblk)) {
quota_error(dquot->dq_sb, "dquota write failed");
if (ret >= 0)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index f1ab360..1c26279 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
struct v2r0_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
if (qtree_entry_unused(info, dp))
d->dqb_itime = cpu_to_le64(1);
}
@@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
{
struct v2r0_disk_dqblk *d = dp;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+ struct qown qown;
if (qtree_entry_unused(info, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+ qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+ return qown_eq(qown, dquot->dq_own);
}
static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
@@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
struct v2r1_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
if (qtree_entry_unused(info, dp))
d->dqb_itime = cpu_to_le64(1);
}
@@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
{
struct v2r1_disk_dqblk *d = dp;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+ struct qown qown;
if (qtree_entry_unused(info, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+ qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+ return qown_eq(qown, dquot->dq_own);
}
static int v2_read_dquot(struct dquot *dquot)
{
- return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
}
static int v2_write_dquot(struct dquot *dquot)
{
- return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
}
static int v2_release_dquot(struct dquot *dquot)
{
- return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
}
static int v2_free_file_info(struct super_block *sb, int type)
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index fed504f..589e9c7 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -97,28 +97,29 @@ xfs_fs_set_xstate(
STATIC int
xfs_fs_get_dqblk(
struct super_block *sb,
- int type,
- qid_t id,
+ struct qown qown,
struct fs_disk_quota *fdq)
{
struct xfs_mount *mp = XFS_M(sb);
+ xfs_dqid_t xfs_id;
if (!XFS_IS_QUOTA_RUNNING(mp))
return -ENOSYS;
if (!XFS_IS_QUOTA_ON(mp))
return -ESRCH;
- return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+ xfs_id = from_qown(&init_user_ns, qown);
+ return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qown.type), fdq);
}
STATIC int
xfs_fs_set_dqblk(
struct super_block *sb,
- int type,
- qid_t id,
+ struct qown qown,
struct fs_disk_quota *fdq)
{
struct xfs_mount *mp = XFS_M(sb);
+ xfs_dqid_t xfs_id;
if (sb->s_flags & MS_RDONLY)
return -EROFS;
@@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
if (!XFS_IS_QUOTA_ON(mp))
return -ESRCH;
- return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+ xfs_id = from_qown(&init_user_ns, qown);
+ return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qown.type), fdq);
}
const struct quotactl_ops xfs_quotactl_operations = {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index bcb6054..3e9fbb8 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -575,12 +575,14 @@ xfs_quota_warn(
struct xfs_dquot *dqp,
int type)
{
+ int qtype;
+ struct qown qown;
/* no warnings for project quotas - we just return ENOSPC later */
if (dqp->dq_flags & XFS_DQ_PROJ)
return;
- quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
- be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
- type);
+ qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
+ qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
+ quota_send_warning(qown, mp->m_super->s_dev, type);
}
/*
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 524ede8..6ebb782 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -181,10 +181,161 @@ enum {
#include <linux/dqblk_v2.h>
#include <linux/atomic.h>
+#include <linux/uidgid.h>
typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
typedef long long qsize_t; /* Type in which we store sizes */
+struct qown { /* Type in which we store the quota owner */
+ union {
+ kuid_t uid;
+ kgid_t gid;
+ unsigned int prj;
+ };
+ int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
+};
+
+static inline bool qown_eq(struct qown left, struct qown right)
+{
+ if (left.type != right.type)
+ return false;
+ switch(left.type) {
+ case USRQUOTA:
+ return uid_eq(left.uid, right.uid);
+ case GRPQUOTA:
+ return gid_eq(left.gid, right.gid);
+ case XQM_PRJQUOTA:
+ return left.prj == right.prj;
+ default:
+ BUG();
+ }
+}
+
+static inline bool qown_lt(struct qown left, struct qown right)
+{
+ if (left.type < right.type)
+ return true;
+ if (left.type > right.type)
+ return false;
+ switch (left.type) {
+ case USRQUOTA:
+ return uid_lt(left.uid, right.uid);
+ case GRPQUOTA:
+ return gid_lt(left.gid, right.gid);
+ case XQM_PRJQUOTA:
+ return left.prj < right.prj;
+ default:
+ BUG();
+ }
+}
+
+static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
+{
+ switch (qown.type) {
+ case USRQUOTA:
+ return from_kuid(user_ns, qown.uid);
+ case GRPQUOTA:
+ return from_kgid(user_ns, qown.gid);
+ case XQM_PRJQUOTA:
+ return (user_ns == &init_user_ns) ? qown.prj : -1;
+ default:
+ BUG();
+ }
+}
+
+static inline u32 from_qown_munged(struct user_namespace *user_ns,
+ struct qown qown)
+{
+ switch (qown.type) {
+ case USRQUOTA:
+ return from_kuid_munged(user_ns, qown.uid);
+ case GRPQUOTA:
+ return from_kgid_munged(user_ns, qown.gid);
+ case XQM_PRJQUOTA:
+ return (user_ns == &init_user_ns) ? qown.prj : -1;
+ default:
+ BUG();
+ }
+}
+
+static inline struct qown make_qown(struct user_namespace *user_ns,
+ int type, qid_t id)
+{
+ struct qown qown;
+
+ qown.type = type;
+ switch (type) {
+ case USRQUOTA:
+ qown.uid = make_kuid(user_ns, id);
+ break;
+ case GRPQUOTA:
+ qown.gid = make_kgid(user_ns, id);
+ break;
+ case XQM_PRJQUOTA:
+ if (user_ns == &init_user_ns)
+ qown.prj = id;
+ else
+ qown.prj = -1;
+ break;
+ default:
+ BUG();
+ }
+ return qown;
+}
+
+static inline struct qown make_qown_invalid(int type)
+{
+ struct qown qown;
+
+ qown.type = type;
+ switch (type) {
+ case USRQUOTA:
+ qown.uid = INVALID_UID;
+ break;
+ case GRPQUOTA:
+ qown.gid = INVALID_GID;
+ break;
+ case XQM_PRJQUOTA:
+ qown.prj = -1;
+ break;
+ default:
+ BUG();
+ }
+ return qown;
+}
+
+static inline struct qown make_qown_uid(kuid_t uid)
+{
+ struct qown qown = {
+ .type = USRQUOTA,
+ .uid = uid,
+ };
+ return qown;
+}
+
+static inline struct qown make_qown_gid(kgid_t gid)
+{
+ struct qown qown = {
+ .type = GRPQUOTA,
+ .gid = gid,
+ };
+ return qown;
+}
+
+static inline bool qown_valid(struct qown qown)
+{
+ switch (qown.type) {
+ case USRQUOTA:
+ return uid_valid(qown.uid);
+ case GRPQUOTA:
+ return gid_valid(qown.gid);
+ case XQM_PRJQUOTA:
+ return qown.prj != (unsigned int)-1;
+ default:
+ BUG();
+ }
+}
+
extern spinlock_t dq_data_lock;
/* Maximal numbers of writes for quota operation (insert/delete/update)
@@ -294,10 +445,9 @@ struct dquot {
atomic_t dq_count; /* Use count */
wait_queue_head_t dq_wait_unused; /* Wait queue for dquot to become unused */
struct super_block *dq_sb; /* superblock this applies to */
- unsigned int dq_id; /* ID this applies to (uid, gid) */
+ struct qown dq_own; /* ID this applies to (uid, gid) */
loff_t dq_off; /* Offset of dquot on disk */
unsigned long dq_flags; /* See DQ_* */
- short dq_type; /* Type of quota */
struct mem_dqblk dq_dqb; /* Diskquota usage */
};
@@ -336,8 +486,8 @@ struct quotactl_ops {
int (*quota_sync)(struct super_block *, int);
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
- int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
- int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+ int (*get_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
+ int (*set_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
int (*set_xstate)(struct super_block *, unsigned int, int);
};
@@ -386,10 +536,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
}
#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+extern void quota_send_warning(struct qown qown, dev_t dev,
const char warntype);
#else
-static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+static inline void quota_send_warning(struct qown qown, dev_t dev,
const char warntype)
{
return;
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ec6b65f..ed9a5e4 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,7 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
void dquot_initialize(struct inode *inode);
void dquot_drop(struct inode *inode);
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
+struct dquot *dqget(struct super_block *sb, struct qown qown);
void dqput(struct dquot *dquot);
int dquot_scan_active(struct super_block *sb,
int (*fn)(struct dquot *dquot, unsigned long priv),
@@ -87,9 +87,9 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
int dquot_quota_sync(struct super_block *sb, int type);
int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown id,
struct fs_disk_quota *di);
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown id,
struct fs_disk_quota *di);
int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
diff --git a/init/Kconfig b/init/Kconfig
index 2a388e5..a0bccce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,8 +928,6 @@ config UIDGID_CONVERTED
depends on IMA = n
depends on EVM = n
depends on FS_POSIX_ACL = n
- depends on QUOTA = n
- depends on QUOTACTL = n
# Networking
depends on NET_9P = n
--
1.7.5.4
^ permalink raw reply related
* (unknown),
From: Allen and Violet Large @ 2012-08-28 18:26 UTC (permalink / raw)
Dear Sir/Madam,
This is my fifth times of writting you this email since last year till
date but no response from you.Hope you get this one, as this is a personal
email directed to you. My wife and I won a Jackpot Lotteryof $11.3 million
in July and have voluntarily decided to donate the sum of $500,000.00 USD
to you as part of our own charity project to improve the lot of 10 lucky
individuals all over the world. If you have received this email then you
are one of the lucky recipients and all you have to do is get back with us
so that we can send your details to the payout bank.Please note that you
have to contact my private email for more
informations(allen_violetlarge202@yahoo.co.jp)
You can verify this by visiting the web pages below.
http://www.dailymail.co.uk/news/article-1326473/Canadian-couple-Allen-Violet-Large-away-entire-11-2m-lottery-win.html
Goodluck,
Allen and Violet Large
allen_violetlarge202@yahoo.co.jp
^ permalink raw reply
* Re: [PATCH net-next] net: ipv4: optimize tkey_mismatch
From: David Miller @ 2012-08-28 18:56 UTC (permalink / raw)
To: igorm; +Cc: netdev
In-Reply-To: <1346143938-17167-2-git-send-email-igorm@etf.rs>
From: igorm@etf.rs
Date: Tue, 28 Aug 2012 10:52:18 +0200
> From: Igor Maravic <igorm@etf.rs>
>
> Optimize tkey_mismatch function by using __fls function.
>
> Signed-off-by: Igor Maravic <igorm@etf.rs>
This will actually run slower on architectures like sparc that
don't have special instructions for __fls.
Your TOS "optimization" isn't very useful either since having
TOS routes is very rare.
^ permalink raw reply
* [PATCH] userns: Add basic quota support v4
From: Eric W. Biederman @ 2012-08-28 19:09 UTC (permalink / raw)
To: Jan Kara
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das
In-Reply-To: <20120828175101.GF5146@quack.suse.cz>
Add the data type struct kqid which holds the kernel internal form of
the owning identifier of a quota. struct kqid is a replacement for
the implicit union of uid, gid and project stored in an unsigned int
and the quota type field that is was used in the quota data
structures. Making the data type explicit allows the kuid_t and
kgid_t type safety to propogate more thoroughly through the code,
revealing more places where uid/gid conversions need be made.
Along with the data type struct kqid comes the helper functions
qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,
make_kqid_invalid, make_kqid_uid, make_kqid_gid.
Change struct dquot dq_id to a struct kqid and remove the now
unecessary dq_type.
Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
and dquot_set_dqblk to use struct kqid.
Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
the change in quota structures and signatures. The ocfs2 changes are
larger than most because of the extensive tracing throughout the ocfs2
quota code that prints out dq_id.
v4:
- Rename struct qown struct kqid and associated changes
to the naming of the helper functions.
- Use qid_t to hold the userspace identifier representation
of quota identifiers in all new code.
v3:
- Add missing negation on qown_valid
v2:
- Renamed qown_t struct qown
- Added the quota type to struct qown.
- Removed enum quota_type (In this patch it was just noise)
- Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
- Taught qown to handle xfs project ids (but only in init_user_ns).
Q_XGETQUOTA calls .get_quotblk with project ids.
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Ben Myers <bpm@sgi.com>
Cc: Alex Elder <elder@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
fs/ext3/super.c | 2 +-
fs/ext4/super.c | 2 +-
fs/gfs2/quota.c | 52 +++++++++------
fs/ocfs2/file.c | 6 +-
fs/ocfs2/quota_global.c | 43 +++++++-----
fs/ocfs2/quota_local.c | 15 +++--
fs/quota/dquot.c | 116 ++++++++++++++++----------------
fs/quota/netlink.c | 10 ++-
fs/quota/quota.c | 28 ++++++--
fs/quota/quota_tree.c | 23 ++++---
fs/quota/quota_v1.c | 12 ++--
fs/quota/quota_v2.c | 26 ++++---
fs/xfs/xfs_quotaops.c | 14 ++--
fs/xfs/xfs_trans_dquot.c | 8 ++-
include/linux/quota.h | 162 ++++++++++++++++++++++++++++++++++++++++++++--
include/linux/quotaops.h | 6 +-
init/Kconfig | 2 -
17 files changed, 364 insertions(+), 163 deletions(-)
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..73e42f5 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2814,7 +2814,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
static inline struct inode *dquot_to_inode(struct dquot *dquot)
{
- return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
}
static int ext3_write_dquot(struct dquot *dquot)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..78e6036 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4796,7 +4796,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
static inline struct inode *dquot_to_inode(struct dquot *dquot)
{
- return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
}
static int ext4_write_dquot(struct dquot *dquot)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..e27f8d6 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
return 0;
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+ int qtype;
+ struct kqid qid;
qd = ip->i_res->rs_qa_qd[x];
if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
@@ -1068,11 +1070,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
value += qd->qd_change;
spin_unlock(&qd_lru_lock);
+ qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
+ qid = make_kqid(&init_user_ns, qtype, qd->qd_id);
if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
print_message(qd, "exceeded");
- quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
- USRQUOTA : GRPQUOTA, qd->qd_id,
- sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+ quota_send_warning(qid, sdp->sd_vfs->s_dev,
+ QUOTA_NL_BHARDWARN);
error = -EDQUOT;
break;
@@ -1081,9 +1084,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
time_after_eq(jiffies, qd->qd_last_warn +
gfs2_tune_get(sdp,
gt_quota_warn_period) * HZ)) {
- quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
- USRQUOTA : GRPQUOTA, qd->qd_id,
- sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
+ quota_send_warning(qid, sdp->sd_vfs->s_dev,
+ QUOTA_NL_BSOFTWARN);
error = print_message(qd, "warning");
qd->qd_last_warn = jiffies;
}
@@ -1469,7 +1471,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
return 0;
}
-static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
+static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
struct fs_disk_quota *fdq)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
@@ -1477,20 +1479,24 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
struct gfs2_quota_data *qd;
struct gfs2_holder q_gh;
int error;
+ int user;
+ u32 gfs_id;
memset(fdq, 0, sizeof(struct fs_disk_quota));
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return -ESRCH; /* Crazy XFS error code */
- if (type == USRQUOTA)
- type = QUOTA_USER;
- else if (type == GRPQUOTA)
- type = QUOTA_GROUP;
+ gfs_id = from_kqid(&init_user_ns, qid);
+
+ if (qid.type == USRQUOTA)
+ user = QUOTA_USER;
+ else if (qid.type == GRPQUOTA)
+ user = QUOTA_GROUP;
else
return -EINVAL;
- error = qd_get(sdp, type, id, &qd);
+ error = qd_get(sdp, user, gfs_id, &qd);
if (error)
return error;
error = do_glock(qd, FORCE, &q_gh);
@@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
fdq->d_version = FS_DQUOT_VERSION;
- fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
- fdq->d_id = id;
+ fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+ fdq->d_id = gfs_id;
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
@@ -1514,8 +1520,8 @@ out:
/* GFS2 only supports a subset of the XFS fields */
#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
-static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
- struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb,
+ struct kqid qid, struct fs_disk_quota *fdq)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
int alloc_required;
loff_t offset;
int error;
+ int user;
+ u32 gfs_id;
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return -ESRCH; /* Crazy XFS error code */
- switch(type) {
+ gfs_id = from_kqid(&init_user_ns, qid);
+
+ switch(qid.type) {
case USRQUOTA:
- type = QUOTA_USER;
+ user = QUOTA_USER;
if (fdq->d_flags != FS_USER_QUOTA)
return -EINVAL;
break;
case GRPQUOTA:
- type = QUOTA_GROUP;
+ user = QUOTA_GROUP;
if (fdq->d_flags != FS_GROUP_QUOTA)
return -EINVAL;
break;
@@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
return -EINVAL;
- if (fdq->d_id != id)
+ if (fdq->d_id != gfs_id)
return -EINVAL;
- error = qd_get(sdp, type, id, &qd);
+ error = qd_get(sdp, user, gfs_id, &qd);
if (error)
return error;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 46a1f6d..5a4ee77 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
- transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
- USRQUOTA);
+ transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
if (!transfer_to[USRQUOTA]) {
status = -ESRCH;
goto bail_unlock;
@@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
- transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
- GRPQUOTA);
+ transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
if (!transfer_to[GRPQUOTA]) {
status = -ESRCH;
goto bail_unlock;
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index 0a86e30..dd4deaa 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -95,7 +95,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
struct ocfs2_global_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -112,11 +112,14 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
{
struct ocfs2_global_disk_dqblk *d = dp;
struct ocfs2_mem_dqinfo *oinfo =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+ struct kqid qid;
if (qtree_entry_unused(&oinfo->dqi_gi, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+
+ qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+ return qid_eq(qid, dquot->dq_id);
}
struct qtree_fmt_operations ocfs2_global_ops = {
@@ -475,7 +478,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
{
int err, err2;
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
struct ocfs2_global_disk_dqblk dqblk;
s64 spacechange, inodechange;
@@ -504,7 +507,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
olditime = dquot->dq_dqb.dqb_itime;
oldbtime = dquot->dq_dqb.dqb_btime;
ocfs2_global_disk2memdqb(dquot, &dqblk);
- trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
+ trace_ocfs2_sync_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+ dquot->dq_dqb.dqb_curspace,
(long long)spacechange,
dquot->dq_dqb.dqb_curinodes,
(long long)inodechange);
@@ -555,8 +559,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
err = ocfs2_qinfo_lock(info, freeing);
if (err < 0) {
mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
- " (type=%d, id=%u)\n", dquot->dq_type,
- (unsigned)dquot->dq_id);
+ " (type=%d, id=%u)\n", dquot->dq_id.type,
+ (unsigned)from_kqid(&init_user_ns, dquot->dq_id));
goto out;
}
if (freeing)
@@ -591,9 +595,10 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
struct ocfs2_super *osb = OCFS2_SB(sb);
int status = 0;
- trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
+ trace_ocfs2_sync_dquot_helper(from_kqid(&init_user_ns, dquot->dq_id),
+ dquot->dq_id.type,
type, sb->s_id);
- if (type != dquot->dq_type)
+ if (type != dquot->dq_id.type)
goto out;
status = ocfs2_lock_global_qf(oinfo, 1);
if (status < 0)
@@ -643,7 +648,8 @@ static int ocfs2_write_dquot(struct dquot *dquot)
struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
int status = 0;
- trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
+ trace_ocfs2_write_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+ dquot->dq_id.type);
handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
if (IS_ERR(handle)) {
@@ -677,11 +683,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
{
handle_t *handle;
struct ocfs2_mem_dqinfo *oinfo =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
int status = 0;
- trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
+ trace_ocfs2_release_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+ dquot->dq_id.type);
mutex_lock(&dquot->dq_lock);
/* Check whether we are not racing with some other dqget() */
@@ -691,7 +698,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
if (status < 0)
goto out;
handle = ocfs2_start_trans(osb,
- ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
+ ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_id.type));
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
@@ -733,13 +740,14 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
int ex = 0;
struct super_block *sb = dquot->dq_sb;
struct ocfs2_super *osb = OCFS2_SB(sb);
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
struct inode *gqinode = info->dqi_gqinode;
int need_alloc = ocfs2_global_qinit_alloc(sb, type);
handle_t *handle;
- trace_ocfs2_acquire_dquot(dquot->dq_id, type);
+ trace_ocfs2_acquire_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+ type);
mutex_lock(&dquot->dq_lock);
/*
* We need an exclusive lock, because we're going to update use count
@@ -821,12 +829,13 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
int sync = 0;
int status;
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
handle_t *handle;
struct ocfs2_super *osb = OCFS2_SB(sb);
- trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
+ trace_ocfs2_mark_dquot_dirty(from_kqid(&init_user_ns, dquot->dq_id),
+ type);
/* In case user set some limits, sync dquot immediately to global
* quota file so that information propagates quicker */
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index f100bf7..27fe7ee 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -501,7 +501,9 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
}
dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
ol_dqblk_block_off(sb, chunk, bit));
- dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
+ dquot = dqget(sb,
+ make_kqid(&init_user_ns, type,
+ le64_to_cpu(dqblk->dqb_id)));
if (!dquot) {
status = -EIO;
mlog(ML_ERROR, "Failed to get quota structure "
@@ -881,7 +883,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
+ ol_dqblk_block_offset(sb, od->dq_local_off));
- dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
+ dqblk->dqb_id = cpu_to_le64(from_kqid(&init_user_ns,
+ od->dq_dquot.dq_id));
spin_lock(&dq_data_lock);
dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
od->dq_origspace);
@@ -891,7 +894,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
trace_olq_set_dquot(
(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
- od->dq_dquot.dq_id);
+ from_kqid(&init_user_ns, od->dq_dquot.dq_id));
}
/* Write dquot to local quota file */
@@ -900,7 +903,7 @@ int ocfs2_local_write_dquot(struct dquot *dquot)
struct super_block *sb = dquot->dq_sb;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
struct buffer_head *bh;
- struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_type];
+ struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_id.type];
int status;
status = ocfs2_read_quota_phys_block(lqinode, od->dq_local_phys_blk,
@@ -1221,7 +1224,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
int ocfs2_create_local_dquot(struct dquot *dquot)
{
struct super_block *sb = dquot->dq_sb;
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct inode *lqinode = sb_dqopt(sb)->files[type];
struct ocfs2_quota_chunk *chunk;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1275,7 +1278,7 @@ out:
int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
{
int status;
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
struct super_block *sb = dquot->dq_sb;
struct ocfs2_local_disk_chunk *dchunk;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 36a29b7..f52625c 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -253,11 +253,13 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
static void __dquot_initialize(struct inode *inode, int type);
static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct kqid qid)
{
+ unsigned int id;
unsigned long tmp;
- tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+ id = from_kqid(&init_user_ns, qid);
+ tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - qid.type);
return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
}
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
static inline void insert_dquot_hash(struct dquot *dquot)
{
struct hlist_head *head;
- head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+ head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id);
hlist_add_head(&dquot->dq_hash, head);
}
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
}
static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
- unsigned int id, int type)
+ struct kqid qid)
{
struct hlist_node *node;
struct dquot *dquot;
hlist_for_each (node, dquot_hash+hashent) {
dquot = hlist_entry(node, struct dquot, dq_hash);
- if (dquot->dq_sb == sb && dquot->dq_id == id &&
- dquot->dq_type == type)
+ if (dquot->dq_sb == sb && qid_eq(dquot->dq_id, qid))
return dquot;
}
return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
spin_lock(&dq_list_lock);
if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
- info[dquot->dq_type].dqi_dirty_list);
+ info[dquot->dq_id.type].dqi_dirty_list);
ret = 0;
}
spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
mutex_lock(&dquot->dq_lock);
mutex_lock(&dqopt->dqio_mutex);
if (!test_bit(DQ_READ_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
if (ret < 0)
goto out_iolock;
set_bit(DQ_READ_B, &dquot->dq_flags);
/* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
/* Write the info if needed */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+ ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_id.type);
}
if (ret < 0)
goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
/* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
else
ret = -EIO;
out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
if (atomic_read(&dquot->dq_count) > 1)
goto out_dqlock;
mutex_lock(&dqopt->dqio_mutex);
- if (dqopt->ops[dquot->dq_type]->release_dqblk) {
- ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+ if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
+ ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot);
/* Write the info */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+ ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_id.type);
}
if (ret >= 0)
ret = ret2;
@@ -521,7 +522,7 @@ restart:
list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
if (dquot->dq_sb != sb)
continue;
- if (dquot->dq_type != type)
+ if (dquot->dq_id.type != type)
continue;
/* Wait for dquot users */
if (atomic_read(&dquot->dq_count)) {
@@ -741,7 +742,8 @@ void dqput(struct dquot *dquot)
#ifdef CONFIG_QUOTA_DEBUG
if (!atomic_read(&dquot->dq_count)) {
quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
- quotatypes[dquot->dq_type], dquot->dq_id);
+ quotatypes[dquot->dq_id.type],
+ from_kqid(&init_user_ns, dquot->dq_id));
BUG();
}
#endif
@@ -752,7 +754,7 @@ we_slept:
/* We have more than one user... nothing to do */
atomic_dec(&dquot->dq_count);
/* Releasing dquot during quotaoff phase? */
- if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+ if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&
atomic_read(&dquot->dq_count) == 1)
wake_up(&dquot->dq_wait_unused);
spin_unlock(&dq_list_lock);
@@ -815,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
INIT_LIST_HEAD(&dquot->dq_dirty);
init_waitqueue_head(&dquot->dq_wait_unused);
dquot->dq_sb = sb;
- dquot->dq_type = type;
+ dquot->dq_id = make_kqid_invalid(type);
atomic_set(&dquot->dq_count, 1);
return dquot;
@@ -829,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
* a) checking for quota flags under dq_list_lock and
* b) getting a reference to dquot before we release dq_list_lock
*/
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct kqid qid)
{
- unsigned int hashent = hashfn(sb, id, type);
+ unsigned int hashent = hashfn(sb, qid);
struct dquot *dquot = NULL, *empty = NULL;
- if (!sb_has_quota_active(sb, type))
+ if (!sb_has_quota_active(sb, qid.type))
return NULL;
we_slept:
spin_lock(&dq_list_lock);
spin_lock(&dq_state_lock);
- if (!sb_has_quota_active(sb, type)) {
+ if (!sb_has_quota_active(sb, qid.type)) {
spin_unlock(&dq_state_lock);
spin_unlock(&dq_list_lock);
goto out;
}
spin_unlock(&dq_state_lock);
- dquot = find_dquot(hashent, sb, id, type);
+ dquot = find_dquot(hashent, sb, qid);
if (!dquot) {
if (!empty) {
spin_unlock(&dq_list_lock);
- empty = get_empty_dquot(sb, type);
+ empty = get_empty_dquot(sb, qid.type);
if (!empty)
schedule(); /* Try to wait for a moment... */
goto we_slept;
}
dquot = empty;
empty = NULL;
- dquot->dq_id = id;
+ dquot->dq_id = qid;
/* all dquots go on the inuse_list */
put_inuse(dquot);
/* hash it first so it can be found */
@@ -1129,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
struct dquot_warn {
struct super_block *w_sb;
- qid_t w_dq_id;
- short w_dq_type;
+ struct kqid w_dq_id;
short w_type;
};
@@ -1154,11 +1155,11 @@ static int need_print_warning(struct dquot_warn *warn)
if (!flag_print_warnings)
return 0;
- switch (warn->w_dq_type) {
+ switch (warn->w_dq_id.type) {
case USRQUOTA:
- return current_fsuid() == warn->w_dq_id;
+ return uid_eq(current_fsuid(), warn->w_dq_id.uid);
case GRPQUOTA:
- return in_group_p(warn->w_dq_id);
+ return in_group_p(warn->w_dq_id.gid);
}
return 0;
}
@@ -1184,7 +1185,7 @@ static void print_warning(struct dquot_warn *warn)
tty_write_message(tty, ": warning, ");
else
tty_write_message(tty, ": write failed, ");
- tty_write_message(tty, quotatypes[warn->w_dq_type]);
+ tty_write_message(tty, quotatypes[warn->w_dq_id.type]);
switch (warntype) {
case QUOTA_NL_IHARDWARN:
msg = " file limit reached.\r\n";
@@ -1218,7 +1219,6 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
warn->w_type = warntype;
warn->w_sb = dquot->dq_sb;
warn->w_dq_id = dquot->dq_id;
- warn->w_dq_type = dquot->dq_type;
}
/*
@@ -1236,14 +1236,14 @@ static void flush_warnings(struct dquot_warn *warn)
#ifdef CONFIG_PRINT_QUOTA_WARNING
print_warning(&warn[i]);
#endif
- quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+ quota_send_warning(warn[i].w_dq_id,
warn[i].w_sb->s_dev, warn[i].w_type);
}
}
static int ignore_hardlimit(struct dquot *dquot)
{
- struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
return capable(CAP_SYS_RESOURCE) &&
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1256,7 +1256,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
{
qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
- if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1281,7 +1281,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
dquot->dq_dqb.dqb_itime == 0) {
prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
dquot->dq_dqb.dqb_itime = get_seconds() +
- sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;
}
return 0;
@@ -1294,7 +1294,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
qsize_t tspace;
struct super_block *sb = dquot->dq_sb;
- if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(sb, dquot->dq_id.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1325,7 +1325,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
if (!prealloc) {
prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
dquot->dq_dqb.dqb_btime = get_seconds() +
- sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+ sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;
}
else
/*
@@ -1344,7 +1344,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
- !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+ !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type))
return QUOTA_NL_NOWARN;
newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1390,7 +1390,6 @@ static int dquot_active(const struct inode *inode)
*/
static void __dquot_initialize(struct inode *inode, int type)
{
- unsigned int id = 0;
int cnt;
struct dquot *got[MAXQUOTAS];
struct super_block *sb = inode->i_sb;
@@ -1403,18 +1402,19 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First get references to structures we might need. */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct kqid qid;
got[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
switch (cnt) {
case USRQUOTA:
- id = inode->i_uid;
+ qid = make_kqid_uid(inode->i_uid);
break;
case GRPQUOTA:
- id = inode->i_gid;
+ qid = make_kqid_gid(inode->i_gid);
break;
}
- got[cnt] = dqget(sb, id, cnt);
+ got[cnt] = dqget(sb, qid);
}
down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1897,10 +1897,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
if (!dquot_active(inode))
return 0;
- if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
- transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
- if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
- transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+ if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+ transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
+ if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+ transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
ret = __dquot_transfer(inode, transfer_to);
dqput_all(transfer_to);
@@ -2360,9 +2360,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
- di->d_flags = dquot->dq_type == USRQUOTA ?
+ di->d_flags = dquot->dq_id.type == USRQUOTA ?
FS_USER_QUOTA : FS_GROUP_QUOTA;
- di->d_id = dquot->dq_id;
+ di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
spin_lock(&dq_data_lock);
di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2376,12 +2376,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
spin_unlock(&dq_data_lock);
}
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
struct fs_disk_quota *di)
{
struct dquot *dquot;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qid);
if (!dquot)
return -ESRCH;
do_get_dqblk(dquot, di);
@@ -2401,7 +2401,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
- struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
return -EINVAL;
@@ -2488,13 +2488,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
return 0;
}
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
struct fs_disk_quota *di)
{
struct dquot *dquot;
int rc;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qid);
if (!dquot) {
rc = -ESRCH;
goto out;
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index d67908b..16e8abb 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
*
*/
-void quota_send_warning(short type, unsigned int id, dev_t dev,
+void quota_send_warning(struct kqid qid, dev_t dev,
const char warntype)
{
static atomic_t seq;
@@ -56,10 +56,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
"VFS: Cannot store netlink header in quota warning.\n");
goto err_out;
}
- ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+ ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qid.type);
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+ ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
+ from_kqid_munged(&init_user_ns, qid));
if (ret)
goto attr_err_out;
ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
@@ -71,7 +72,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+ ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
+ from_kuid_munged(&init_user_ns, current_uid()));
if (ret)
goto attr_err_out;
genlmsg_end(skb, msg_head);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..ff0135d 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
/* allow to query information for dquots we "own" */
case Q_GETQUOTA:
case Q_XGETQUOTA:
- if ((type == USRQUOTA && current_euid() == id) ||
- (type == GRPQUOTA && in_egroup_p(id)))
+ if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
+ (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
break;
/*FALLTHROUGH*/
default:
@@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
static int quota_getquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
+ struct kqid qid;
struct fs_disk_quota fdq;
struct if_dqblk idq;
int ret;
if (!sb->s_qcop->get_dqblk)
return -ENOSYS;
- ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+ qid = make_kqid(current_user_ns(), type, id);
+ if (!qid_valid(qid))
+ return -EINVAL;
+ ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
if (ret)
return ret;
copy_to_if_dqblk(&idq, &fdq);
@@ -176,13 +180,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
{
struct fs_disk_quota fdq;
struct if_dqblk idq;
+ struct kqid qid;
if (copy_from_user(&idq, addr, sizeof(idq)))
return -EFAULT;
if (!sb->s_qcop->set_dqblk)
return -ENOSYS;
+ qid = make_kqid(current_user_ns(), type, id);
+ if (!qid_valid(qid))
+ return -EINVAL;
copy_from_if_dqblk(&fdq, &idq);
- return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+ return sb->s_qcop->set_dqblk(sb, qid, &fdq);
}
static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -213,23 +221,31 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
struct fs_disk_quota fdq;
+ struct kqid qid;
if (copy_from_user(&fdq, addr, sizeof(fdq)))
return -EFAULT;
if (!sb->s_qcop->set_dqblk)
return -ENOSYS;
- return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+ qid = make_kqid(current_user_ns(), type, id);
+ if (!qid_valid(qid))
+ return -EINVAL;
+ return sb->s_qcop->set_dqblk(sb, qid, &fdq);
}
static int quota_getxquota(struct super_block *sb, int type, qid_t id,
void __user *addr)
{
struct fs_disk_quota fdq;
+ struct kqid qid;
int ret;
if (!sb->s_qcop->get_dqblk)
return -ENOSYS;
- ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+ qid = make_kqid(current_user_ns(), type, id);
+ if (!qid_valid(qid))
+ return -EINVAL;
+ ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
return -EFAULT;
return ret;
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index e41c1becf..3534c22 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
#define __QUOTA_QT_PARANOIA
-static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
+static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth)
{
unsigned int epb = info->dqi_usable_bs >> 2;
+ qid_t id;
+ id = from_kqid(&init_user_ns, qid);
depth = info->dqi_qtree_depth - depth - 1;
while (depth--)
id /= epb;
@@ -244,7 +246,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
/* This is enough as the block is already zeroed and the entry
* list is empty... */
info->dqi_free_entry = blk;
- mark_info_dirty(dquot->dq_sb, dquot->dq_type);
+ mark_info_dirty(dquot->dq_sb, dquot->dq_id.type);
}
/* Block will be full? */
if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
@@ -357,7 +359,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
*/
int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct super_block *sb = dquot->dq_sb;
ssize_t ret;
char *ddquot = getdqbuf(info->dqi_entry_size);
@@ -538,8 +540,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
ddquot += info->dqi_entry_size;
}
if (i == qtree_dqstr_in_blk(info)) {
- quota_error(dquot->dq_sb, "Quota for id %u referenced "
- "but not present", dquot->dq_id);
+ quota_error(dquot->dq_sb,
+ "Quota for id %u referenced but not present",
+ from_kqid(&init_user_ns, dquot->dq_id));
ret = -EIO;
goto out_buf;
} else {
@@ -589,7 +592,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct super_block *sb = dquot->dq_sb;
loff_t offset;
char *ddquot;
@@ -607,8 +610,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
offset = find_dqentry(info, dquot);
if (offset <= 0) { /* Entry not present? */
if (offset < 0)
- quota_error(sb, "Can't read quota structure "
- "for id %u", dquot->dq_id);
+ quota_error(sb,"Can't read quota structure "
+ "for id %u",
+ from_kqid(&init_user_ns,
+ dquot->dq_id));
dquot->dq_off = 0;
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -626,7 +631,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
if (ret >= 0)
ret = -EIO;
quota_error(sb, "Error while reading quota structure for id %u",
- dquot->dq_id);
+ from_kqid(&init_user_ns, dquot->dq_id));
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
kfree(ddquot);
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 34b37a6..469c684 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
static int v1_read_dqblk(struct dquot *dquot)
{
- int type = dquot->dq_type;
+ int type = dquot->dq_id.type;
struct v1_disk_dqblk dqblk;
if (!sb_dqopt(dquot->dq_sb)->files[type])
@@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
/* Set structure to 0s in case read fails/is after end of file */
memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
- sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
+ sizeof(struct v1_disk_dqblk),
+ v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)
static int v1_commit_dqblk(struct dquot *dquot)
{
- short type = dquot->dq_type;
+ short type = dquot->dq_id.type;
ssize_t ret;
struct v1_disk_dqblk dqblk;
v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
- if (dquot->dq_id == 0) {
+ if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
+ ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
dqblk.dqb_btime =
sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
dqblk.dqb_itime =
@@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
if (sb_dqopt(dquot->dq_sb)->files[type])
ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
(char *)&dqblk, sizeof(struct v1_disk_dqblk),
- v1_dqoff(dquot->dq_id));
+ v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
if (ret != sizeof(struct v1_disk_dqblk)) {
quota_error(dquot->dq_sb, "dquota write failed");
if (ret >= 0)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index f1ab360..928cb22 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
struct v2r0_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
if (qtree_entry_unused(info, dp))
d->dqb_itime = cpu_to_le64(1);
}
@@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
{
struct v2r0_disk_dqblk *d = dp;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+ struct kqid qid;
if (qtree_entry_unused(info, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+ qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+ return qid_eq(qid, dquot->dq_id);
}
static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
@@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
struct v2r1_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
- d->dqb_id = cpu_to_le32(dquot->dq_id);
+ d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
if (qtree_entry_unused(info, dp))
d->dqb_itime = cpu_to_le64(1);
}
@@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
{
struct v2r1_disk_dqblk *d = dp;
struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+ struct kqid qid;
if (qtree_entry_unused(info, dp))
return 0;
- return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+ qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+ return qid_eq(qid, dquot->dq_id);
}
static int v2_read_dquot(struct dquot *dquot)
{
- return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
}
static int v2_write_dquot(struct dquot *dquot)
{
- return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
}
static int v2_release_dquot(struct dquot *dquot)
{
- return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+ return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
}
static int v2_free_file_info(struct super_block *sb, int type)
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index fed504f..96944c0 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -97,28 +97,29 @@ xfs_fs_set_xstate(
STATIC int
xfs_fs_get_dqblk(
struct super_block *sb,
- int type,
- qid_t id,
+ struct kqid qid,
struct fs_disk_quota *fdq)
{
struct xfs_mount *mp = XFS_M(sb);
+ xfs_dqid_t xfs_id;
if (!XFS_IS_QUOTA_RUNNING(mp))
return -ENOSYS;
if (!XFS_IS_QUOTA_ON(mp))
return -ESRCH;
- return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+ xfs_id = from_kqid(&init_user_ns, qid);
+ return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qid.type), fdq);
}
STATIC int
xfs_fs_set_dqblk(
struct super_block *sb,
- int type,
- qid_t id,
+ struct kqid qid,
struct fs_disk_quota *fdq)
{
struct xfs_mount *mp = XFS_M(sb);
+ xfs_dqid_t xfs_id;
if (sb->s_flags & MS_RDONLY)
return -EROFS;
@@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
if (!XFS_IS_QUOTA_ON(mp))
return -ESRCH;
- return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+ xfs_id = from_kqid(&init_user_ns, qid);
+ return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qid.type), fdq);
}
const struct quotactl_ops xfs_quotactl_operations = {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index bcb6054..46de393 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -575,12 +575,14 @@ xfs_quota_warn(
struct xfs_dquot *dqp,
int type)
{
+ int qtype;
+ struct kqid qid;
/* no warnings for project quotas - we just return ENOSPC later */
if (dqp->dq_flags & XFS_DQ_PROJ)
return;
- quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
- be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
- type);
+ qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
+ qid = make_kqid(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
+ quota_send_warning(qid, mp->m_super->s_dev, type);
}
/*
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 524ede8..0e73250 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -181,10 +181,161 @@ enum {
#include <linux/dqblk_v2.h>
#include <linux/atomic.h>
+#include <linux/uidgid.h>
typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
typedef long long qsize_t; /* Type in which we store sizes */
+struct kqid { /* Type in which we store the quota identifier */
+ union {
+ kuid_t uid;
+ kgid_t gid;
+ qid_t prj;
+ };
+ int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
+};
+
+static inline bool qid_eq(struct kqid left, struct kqid right)
+{
+ if (left.type != right.type)
+ return false;
+ switch(left.type) {
+ case USRQUOTA:
+ return uid_eq(left.uid, right.uid);
+ case GRPQUOTA:
+ return gid_eq(left.gid, right.gid);
+ case XQM_PRJQUOTA:
+ return left.prj == right.prj;
+ default:
+ BUG();
+ }
+}
+
+static inline bool qid_lt(struct kqid left, struct kqid right)
+{
+ if (left.type < right.type)
+ return true;
+ if (left.type > right.type)
+ return false;
+ switch (left.type) {
+ case USRQUOTA:
+ return uid_lt(left.uid, right.uid);
+ case GRPQUOTA:
+ return gid_lt(left.gid, right.gid);
+ case XQM_PRJQUOTA:
+ return left.prj < right.prj;
+ default:
+ BUG();
+ }
+}
+
+static inline qid_t from_kqid(struct user_namespace *user_ns, struct kqid qid)
+{
+ switch (qid.type) {
+ case USRQUOTA:
+ return from_kuid(user_ns, qid.uid);
+ case GRPQUOTA:
+ return from_kgid(user_ns, qid.gid);
+ case XQM_PRJQUOTA:
+ return (user_ns == &init_user_ns) ? qid.prj : -1;
+ default:
+ BUG();
+ }
+}
+
+static inline qid_t from_kqid_munged(struct user_namespace *user_ns,
+ struct kqid qid)
+{
+ switch (qid.type) {
+ case USRQUOTA:
+ return from_kuid_munged(user_ns, qid.uid);
+ case GRPQUOTA:
+ return from_kgid_munged(user_ns, qid.gid);
+ case XQM_PRJQUOTA:
+ return (user_ns == &init_user_ns) ? qid.prj : -1;
+ default:
+ BUG();
+ }
+}
+
+static inline struct kqid make_kqid(struct user_namespace *user_ns,
+ int type, qid_t qid)
+{
+ struct kqid kqid;
+
+ kqid.type = type;
+ switch (type) {
+ case USRQUOTA:
+ kqid.uid = make_kuid(user_ns, qid);
+ break;
+ case GRPQUOTA:
+ kqid.gid = make_kgid(user_ns, qid);
+ break;
+ case XQM_PRJQUOTA:
+ if (user_ns == &init_user_ns)
+ kqid.prj = qid;
+ else
+ kqid.prj = -1;
+ break;
+ default:
+ BUG();
+ }
+ return kqid;
+}
+
+static inline struct kqid make_kqid_invalid(int type)
+{
+ struct kqid kqid;
+
+ kqid.type = type;
+ switch (type) {
+ case USRQUOTA:
+ kqid.uid = INVALID_UID;
+ break;
+ case GRPQUOTA:
+ kqid.gid = INVALID_GID;
+ break;
+ case XQM_PRJQUOTA:
+ kqid.prj = -1;
+ break;
+ default:
+ BUG();
+ }
+ return kqid;
+}
+
+static inline struct kqid make_kqid_uid(kuid_t uid)
+{
+ struct kqid kqid = {
+ .type = USRQUOTA,
+ .uid = uid,
+ };
+ return kqid;
+}
+
+static inline struct kqid make_kqid_gid(kgid_t gid)
+{
+ struct kqid kqid = {
+ .type = GRPQUOTA,
+ .gid = gid,
+ };
+ return kqid;
+}
+
+static inline bool qid_valid(struct kqid qid)
+{
+ switch (qid.type) {
+ case USRQUOTA:
+ return uid_valid(qid.uid);
+ case GRPQUOTA:
+ return gid_valid(qid.gid);
+ case XQM_PRJQUOTA:
+ return qid.prj != (qid_t)-1;
+ default:
+ BUG();
+ }
+}
+
extern spinlock_t dq_data_lock;
/* Maximal numbers of writes for quota operation (insert/delete/update)
@@ -294,10 +445,9 @@ struct dquot {
atomic_t dq_count; /* Use count */
wait_queue_head_t dq_wait_unused; /* Wait queue for dquot to become unused */
struct super_block *dq_sb; /* superblock this applies to */
- unsigned int dq_id; /* ID this applies to (uid, gid) */
+ struct kqid dq_id; /* ID this applies to (uid, gid, prj) */
loff_t dq_off; /* Offset of dquot on disk */
unsigned long dq_flags; /* See DQ_* */
- short dq_type; /* Type of quota */
struct mem_dqblk dq_dqb; /* Diskquota usage */
};
@@ -336,8 +486,8 @@ struct quotactl_ops {
int (*quota_sync)(struct super_block *, int);
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
- int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
- int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+ int (*get_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
+ int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
int (*set_xstate)(struct super_block *, unsigned int, int);
};
@@ -386,10 +536,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
}
#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+extern void quota_send_warning(struct kqid qid, dev_t dev,
const char warntype);
#else
-static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+static inline void quota_send_warning(struct kqid qid, dev_t dev,
const char warntype)
{
return;
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ec6b65f..1c50093 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,7 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
void dquot_initialize(struct inode *inode);
void dquot_drop(struct inode *inode);
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
+struct dquot *dqget(struct super_block *sb, struct kqid qid);
void dqput(struct dquot *dquot);
int dquot_scan_active(struct super_block *sb,
int (*fn)(struct dquot *dquot, unsigned long priv),
@@ -87,9 +87,9 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
int dquot_quota_sync(struct super_block *sb, int type);
int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct kqid id,
struct fs_disk_quota *di);
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct kqid id,
struct fs_disk_quota *di);
int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
diff --git a/init/Kconfig b/init/Kconfig
index 2a388e5..a0bccce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,8 +928,6 @@ config UIDGID_CONVERTED
depends on IMA = n
depends on EVM = n
depends on FS_POSIX_ACL = n
- depends on QUOTA = n
- depends on QUOTACTL = n
# Networking
depends on NET_9P = n
--
1.7.5.4
^ permalink raw reply related
* Re: [PATCH] skbuff: remove pointless conditional before kfree_skb()
From: Flavio Leitner @ 2012-08-28 19:17 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Wei Yongjun, davem, yongjun_wei, netdev
In-Reply-To: <1346163154.3571.6.camel@edumazet-glaptop>
On Tue, 28 Aug 2012 07:12:34 -0700
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Tue, 2012-08-28 at 21:10 +0800, Wei Yongjun wrote:
> > From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> >
> > Remove pointless conditional before kfree_skb().
> >
> > Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > ---
> > include/linux/skbuff.h | 3 +--
> > 1 file changed, 1 insertion(+), 2 deletions(-)
> >
> > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > index 7632c87..0b846d9 100644
> > --- a/include/linux/skbuff.h
> > +++ b/include/linux/skbuff.h
> > @@ -2464,8 +2464,7 @@ static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
> > }
> > static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
> > {
> > - if (skb)
> > - kfree_skb(skb);
> > + kfree_skb(skb);
> > }
> > #endif
> > #ifdef CONFIG_BRIDGE_NETFILTER
> >
>
>
> Its not exactly pointless.
>
> Its a tradeoff between kernel code size, and ability for cpu to predict
> a branch in kfree_skb()
>
> This test is in hot path, and therefore this patch can potentially have
> a performance impact.
>
> I really think most kfree_skb() calls are done with a non NULL param,
> so the branch prediction is good.
>
> But after this patch, things are totally different.
>
But then the kfree_skb() is somewhat misleading because it does
check for NULL argument. One would have to remember if it's in
hot path or not. So, what about a new macro to pair with
kfree_skb()? That would document the code and would also
make easier to remember about the performance issue.
For instance:
/* kfree_skb() version to be used in hot code path
* as the branch prediction can improve performance
*/
#define kfree_skb_hot(skb) \
if (skb) \
kfree_skb(skb) \
fbl
^ permalink raw reply
* Re: IPv4 header extension for IPv6 translation support
From: Eric W. Biederman @ 2012-08-28 19:32 UTC (permalink / raw)
To: Vlad Maraev; +Cc: netdev
In-Reply-To: <CAK617oRJypmo3025f8PZSv=Rehb3NjqyNp=bQjnRFWwaGjGXzw@mail.gmail.com>
Vlad Maraev <maraevvb@gmail.com> writes:
> Hi,
> I would be happy to get some feedback on my idea that is described below.
> I need to tell that I'm a newbie in Linux kernel development but it
> would be interesting for me to estimate complexity and to implement
> this in practice.
You are going over territory that has been rather thoroughly explored
already.
You might want to make a study of the rfcs from the ietf that document
why the existing solutions were chosen.
But for a few hints.
- It is possible to implement prefix translation and avoid the need for
huge NAT state tables. State tables are only needed when you don't
have enough addresses or want the benefits of connection tracking.
- Any extention to ipv4 to give it larger addresses is roughly of the
same difficulty as implementing ipv6. In fact it is more difficult
because ipv6 is present in most end devices today, it is the network
links that are the bottle-neck in rolling out ipv6.
For the best interoperatiblity the best transition strategy remains
dual-stack. With native ipv6 connectivity and some flavor of ipv4
connectivity (native, dual-stack-lite, or 646xlate).
Eric
^ permalink raw reply
* Re: [PATCH V2 1/2] ipvs: IPv6 MTU checking cleanup and bugfix
From: Patrick McHardy @ 2012-08-28 20:08 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev, lvs-devel, Julian Anastasov, Simon Horman,
Pablo Neira Ayuso, Hans Schillstrom, Wensong Zhang,
netfilter-devel
In-Reply-To: <20120828142122.11475.71918.stgit@dragon>
On Tue, 28 Aug 2012, Jesper Dangaard Brouer wrote:
> Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using
> a common helper function __mtu_check_toobig_v6().
>
> The MTU check for tunnel mode can also use this helper as
> ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) is qual to
> skb->len. And the 'mtu' variable have been adjusted before
> calling helper.
>
> Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6()
> were missing a check for skb_is_gso().
>
> This bug e.g. caused issues for KVM IPVS setups, where different
> Segmentation Offloading techniques are utilized, between guests,
> via the virtio driver. This resulted in very bad performance,
> due to the ICMPv6 "too big" messages didn't affect the sender.
>
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Applied to my nf-nat-ipv6 tree.
^ permalink raw reply
* Re: [PATCH] skbuff: remove pointless conditional before kfree_skb()
From: Eric Dumazet @ 2012-08-28 20:09 UTC (permalink / raw)
To: Flavio Leitner; +Cc: Wei Yongjun, davem, yongjun_wei, netdev
In-Reply-To: <20120828161719.6faca38c@obelix.rh>
On Tue, 2012-08-28 at 16:17 -0300, Flavio Leitner wrote:
> On Tue, 28 Aug 2012 07:12:34 -0700
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
> > On Tue, 2012-08-28 at 21:10 +0800, Wei Yongjun wrote:
> > > From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > >
> > > Remove pointless conditional before kfree_skb().
> > >
> > > Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > > ---
> > > include/linux/skbuff.h | 3 +--
> > > 1 file changed, 1 insertion(+), 2 deletions(-)
> > >
> > > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > > index 7632c87..0b846d9 100644
> > > --- a/include/linux/skbuff.h
> > > +++ b/include/linux/skbuff.h
> > > @@ -2464,8 +2464,7 @@ static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
> > > }
> > > static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
> > > {
> > > - if (skb)
> > > - kfree_skb(skb);
> > > + kfree_skb(skb);
> > > }
> > > #endif
> > > #ifdef CONFIG_BRIDGE_NETFILTER
> > >
> >
> >
> > Its not exactly pointless.
> >
> > Its a tradeoff between kernel code size, and ability for cpu to predict
> > a branch in kfree_skb()
> >
> > This test is in hot path, and therefore this patch can potentially have
> > a performance impact.
> >
> > I really think most kfree_skb() calls are done with a non NULL param,
> > so the branch prediction is good.
> >
> > But after this patch, things are totally different.
> >
>
> But then the kfree_skb() is somewhat misleading because it does
> check for NULL argument. One would have to remember if it's in
> hot path or not. So, what about a new macro to pair with
> kfree_skb()? That would document the code and would also
> make easier to remember about the performance issue.
>
> For instance:
> /* kfree_skb() version to be used in hot code path
> * as the branch prediction can improve performance
> */
> #define kfree_skb_hot(skb) \
> if (skb) \
> kfree_skb(skb) \
Really kfree_skb() is not misleading at all :
if (unlikely(!skb))
return;
So while its _perfectly_ valid to call kfree_skb(NULL), this code
expect callers to not abuse this facility.
And nf_conntrack_put_reasm() is called from skb_release_head_state()
We know in this code that most of the time, skb will be NULL.
I dont think we need to add another API for this case and see one
hundred patches coming _trying_ to use this new API.
Just review patches and shout if something bad happens.
^ permalink raw reply
* Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes
From: Patrick McHardy @ 2012-08-28 20:10 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev, lvs-devel, Julian Anastasov, Simon Horman,
Pablo Neira Ayuso, Hans Schillstrom, Wensong Zhang,
netfilter-devel
In-Reply-To: <20120828142248.11475.15917.stgit@dragon>
On Tue, 28 Aug 2012, Jesper Dangaard Brouer wrote:
> This patch is necessary, to make IPVS work, after Patrick McHardys
> IPv6 NAT defragmentation changes.
>
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
I've folded this into the defragmentation patch to avoid temporary
breakage. Thanks Jesper.
^ permalink raw reply
* Re: [PATCH] skbuff: remove pointless conditional before kfree_skb()
From: Flavio Leitner @ 2012-08-28 20:39 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Wei Yongjun, davem, yongjun_wei, netdev
In-Reply-To: <1346184598.3571.16.camel@edumazet-glaptop>
On Tue, 28 Aug 2012 13:09:58 -0700
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Tue, 2012-08-28 at 16:17 -0300, Flavio Leitner wrote:
> > On Tue, 28 Aug 2012 07:12:34 -0700
> > Eric Dumazet <eric.dumazet@gmail.com> wrote:
> >
> > > On Tue, 2012-08-28 at 21:10 +0800, Wei Yongjun wrote:
> > > > From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > > >
> > > > Remove pointless conditional before kfree_skb().
> > > >
> > > > Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > > > ---
> > > > include/linux/skbuff.h | 3 +--
> > > > 1 file changed, 1 insertion(+), 2 deletions(-)
> > > >
> > > > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > > > index 7632c87..0b846d9 100644
> > > > --- a/include/linux/skbuff.h
> > > > +++ b/include/linux/skbuff.h
> > > > @@ -2464,8 +2464,7 @@ static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
> > > > }
> > > > static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
> > > > {
> > > > - if (skb)
> > > > - kfree_skb(skb);
> > > > + kfree_skb(skb);
> > > > }
> > > > #endif
> > > > #ifdef CONFIG_BRIDGE_NETFILTER
> > > >
> > >
> > >
> > > Its not exactly pointless.
> > >
> > > Its a tradeoff between kernel code size, and ability for cpu to predict
> > > a branch in kfree_skb()
> > >
> > > This test is in hot path, and therefore this patch can potentially have
> > > a performance impact.
> > >
> > > I really think most kfree_skb() calls are done with a non NULL param,
> > > so the branch prediction is good.
> > >
> > > But after this patch, things are totally different.
> > >
> >
> > But then the kfree_skb() is somewhat misleading because it does
> > check for NULL argument. One would have to remember if it's in
> > hot path or not. So, what about a new macro to pair with
> > kfree_skb()? That would document the code and would also
> > make easier to remember about the performance issue.
> >
> > For instance:
> > /* kfree_skb() version to be used in hot code path
> > * as the branch prediction can improve performance
> > */
> > #define kfree_skb_hot(skb) \
> > if (skb) \
> > kfree_skb(skb) \
>
> Really kfree_skb() is not misleading at all :
>
> if (unlikely(!skb))
> return;
>
> So while its _perfectly_ valid to call kfree_skb(NULL), this code
> expect callers to not abuse this facility.
Well, I don't think that is obvious. Neither the patch's author.
> And nf_conntrack_put_reasm() is called from skb_release_head_state()
>
> We know in this code that most of the time, skb will be NULL.
yeah, but it looks pointless to check the same thing twice.
> I dont think we need to add another API for this case and see one
> hundred patches coming _trying_ to use this new API.
Ok, and what if kfree_skb() becomes a macro that first checks
if the skb is NULL and if not, call the _kfree_skb() to
continue as before?
#define kfree_skb(skb) \
if (skb) \
_kfree_skb(skb) \
void _kfree_skb(struct sk_buff *skb)
{
if (likely(atomic_read(&skb->users) == 1))
smp_rmb();
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_kfree_skb(skb, __builtin_return_address(0));
__kfree_skb(skb);
}
Same API which would work for either use-cases. At the cost of
additional size in the binary.
> Just review patches and shout if something bad happens.
I hope we always have you around to catch these cases :)
fbl
^ permalink raw reply
* [PATCH 02/19] Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using a common helper function __mtu_check_toobig_v6().
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
From: Jesper Dangaard Brouer <brouer@redhat.com>
The MTU check for tunnel mode can also use this helper as
ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) is qual to
skb->len. And the 'mtu' variable have been adjusted before
calling helper.
Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6()
were missing a check for skb_is_gso().
This bug e.g. caused issues for KVM IPVS setups, where different
Segmentation Offloading techniques are utilized, between guests,
via the virtio driver. This resulted in very bad performance,
due to the ICMPv6 "too big" messages didn't affect the sender.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
net/netfilter/ipvs/ip_vs_xmit.c | 21 +++++++++++++++------
1 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 543a554..67a3978 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -85,6 +85,15 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
return dst;
}
+static inline bool
+__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
+{
+ if (skb->len > mtu && !skb_is_gso(skb)) {
+ return true; /* Packet size violate MTU size */
+ }
+ return false;
+}
+
/* Get route to daddr, update *saddr, optionally bind route to saddr */
static struct rtable *do_output_route4(struct net *net, __be32 daddr,
u32 rtos, int rt_mode, __be32 *saddr)
@@ -491,7 +500,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* MTU checking */
mtu = dst_mtu(&rt->dst);
- if (skb->len > mtu && !skb_is_gso(skb)) {
+ if (__mtu_check_toobig_v6(skb, mtu)) {
if (!skb->dev) {
struct net *net = dev_net(skb_dst(skb)->dev);
@@ -712,7 +721,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* MTU checking */
mtu = dst_mtu(&rt->dst);
- if (skb->len > mtu && !skb_is_gso(skb)) {
+ if (__mtu_check_toobig_v6(skb, mtu)) {
if (!skb->dev) {
struct net *net = dev_net(skb_dst(skb)->dev);
@@ -946,8 +955,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_dst(skb))
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
- if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
- !skb_is_gso(skb)) {
+ /* MTU checking: Notice that 'mtu' have been adjusted before hand */
+ if (__mtu_check_toobig_v6(skb, mtu)) {
if (!skb->dev) {
struct net *net = dev_net(skb_dst(skb)->dev);
@@ -1113,7 +1122,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* MTU checking */
mtu = dst_mtu(&rt->dst);
- if (skb->len > mtu) {
+ if (__mtu_check_toobig_v6(skb, mtu)) {
if (!skb->dev) {
struct net *net = dev_net(skb_dst(skb)->dev);
@@ -1349,7 +1358,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* MTU checking */
mtu = dst_mtu(&rt->dst);
- if (skb->len > mtu && !skb_is_gso(skb)) {
+ if (__mtu_check_toobig_v6(skb, mtu)) {
if (!skb->dev) {
struct net *net = dev_net(skb_dst(skb)->dev);
--
1.7.1
^ permalink raw reply related
* [PATCH 04/19] netfilter: nf_conntrack_ipv6: fix tracking of ICMPv6 error messages containing fragments
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
ICMPv6 error messages are tracked by extracting the conntrack tuple of
the inner packet and looking up the corresponding conntrack entry. Tuple
extraction uses the ->get_l4proto() callback, which in case of fragments
returns NEXTHDR_FRAGMENT instead of the upper protocol, even for the
first fragment when the entire next header is present, resulting in a
failure to find the correct connection tracking entry.
This patch changes ipv6_get_l4proto() to use ipv6_skip_exthdr() instead
of nf_ct_ipv6_skip_exthdr() in order to skip fragment headers when the
fragment offset is zero.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 63 ++---------------------
1 files changed, 6 insertions(+), 57 deletions(-)
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 521ddca..dcf6010 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -64,82 +64,31 @@ static int ipv6_print_tuple(struct seq_file *s,
tuple->src.u3.ip6, tuple->dst.u3.ip6);
}
-/*
- * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
- *
- * This function parses (probably truncated) exthdr set "hdr"
- * of length "len". "nexthdrp" initially points to some place,
- * where type of the first header can be found.
- *
- * It skips all well-known exthdrs, and returns pointer to the start
- * of unparsable area i.e. the first header with unknown type.
- * if success, *nexthdr is updated by type/protocol of this header.
- *
- * NOTES: - it may return pointer pointing beyond end of packet,
- * if the last recognized header is truncated in the middle.
- * - if packet is truncated, so that all parsed headers are skipped,
- * it returns -1.
- * - if packet is fragmented, return pointer of the fragment header.
- * - ESP is unparsable for now and considered like
- * normal payload protocol.
- * - Note also special handling of AUTH header. Thanks to IPsec wizards.
- */
-
-static int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
- u8 *nexthdrp, int len)
-{
- u8 nexthdr = *nexthdrp;
-
- while (ipv6_ext_hdr(nexthdr)) {
- struct ipv6_opt_hdr hdr;
- int hdrlen;
-
- if (len < (int)sizeof(struct ipv6_opt_hdr))
- return -1;
- if (nexthdr == NEXTHDR_NONE)
- break;
- if (nexthdr == NEXTHDR_FRAGMENT)
- break;
- if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
- BUG();
- if (nexthdr == NEXTHDR_AUTH)
- hdrlen = (hdr.hdrlen+2)<<2;
- else
- hdrlen = ipv6_optlen(&hdr);
-
- nexthdr = hdr.nexthdr;
- len -= hdrlen;
- start += hdrlen;
- }
-
- *nexthdrp = nexthdr;
- return start;
-}
-
static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
unsigned int *dataoff, u_int8_t *protonum)
{
unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
- unsigned char pnum;
+ __be16 frag_off;
int protoff;
+ u8 nexthdr;
if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
- &pnum, sizeof(pnum)) != 0) {
+ &nexthdr, sizeof(nexthdr)) != 0) {
pr_debug("ip6_conntrack_core: can't get nexthdr\n");
return -NF_ACCEPT;
}
- protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff);
+ protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
/*
* (protoff == skb->len) mean that the packet doesn't have no data
* except of IPv6 & ext headers. but it's tracked anyway. - YK
*/
- if ((protoff < 0) || (protoff > skb->len)) {
+ if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
return -NF_ACCEPT;
}
*dataoff = protoff;
- *protonum = pnum;
+ *protonum = nexthdr;
return NF_ACCEPT;
}
--
1.7.1
^ permalink raw reply related
* [PATCH 05/19] netfilter: nf_conntrack: restrict NAT helper invocation to IPv4
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
The NAT helpers currently only handle IPv4 packets correctly. Restrict
invocation of the helpers to IPv4 in preparation of IPv6 NAT.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
net/netfilter/nf_conntrack_amanda.c | 3 +-
net/netfilter/nf_conntrack_ftp.c | 3 +-
net/netfilter/nf_conntrack_h323_main.c | 41 ++++++++++++++++++++++---------
net/netfilter/nf_conntrack_irc.c | 3 +-
net/netfilter/nf_conntrack_sip.c | 18 +++++++++----
net/netfilter/nf_conntrack_tftp.c | 3 +-
6 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index f2de8c5..184c0dc 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -154,7 +154,8 @@ static int amanda_help(struct sk_buff *skb,
IPPROTO_TCP, NULL, &port);
nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
- if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
+ if (nf_nat_amanda && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_amanda(skb, ctinfo, off - dataoff,
len, exp);
else if (nf_ct_expect_related(exp) != 0)
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 4bb771d..3e1587e 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -487,7 +487,8 @@ static int help(struct sk_buff *skb,
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook);
- if (nf_nat_ftp && ct->status & IPS_NAT_MASK)
+ if (nf_nat_ftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp);
else {
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 4283b20..517c5e3 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -295,6 +295,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
&ct->tuplehash[!dir].tuple.dst.u3,
sizeof(ct->tuplehash[dir].tuple.src.u3)) &&
(nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook)) &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
ret = nat_rtp_rtcp(skb, ct, ctinfo, data, dataoff,
@@ -353,6 +354,7 @@ static int expect_t120(struct sk_buff *skb,
&ct->tuplehash[!dir].tuple.dst.u3,
sizeof(ct->tuplehash[dir].tuple.src.u3)) &&
(nat_t120 = rcu_dereference(nat_t120_hook)) &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
ret = nat_t120(skb, ct, ctinfo, data, dataoff, taddr,
@@ -688,6 +690,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
&ct->tuplehash[!dir].tuple.dst.u3,
sizeof(ct->tuplehash[dir].tuple.src.u3)) &&
(nat_h245 = rcu_dereference(nat_h245_hook)) &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 &&
ct->status & IPS_NAT_MASK) {
/* NAT needed */
ret = nat_h245(skb, ct, ctinfo, data, dataoff, taddr,
@@ -811,6 +814,7 @@ static int expect_callforwarding(struct sk_buff *skb,
&ct->tuplehash[!dir].tuple.dst.u3,
sizeof(ct->tuplehash[dir].tuple.src.u3)) &&
(nat_callforwarding = rcu_dereference(nat_callforwarding_hook)) &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 &&
ct->status & IPS_NAT_MASK) {
/* Need NAT */
ret = nat_callforwarding(skb, ct, ctinfo, data, dataoff,
@@ -852,7 +856,8 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
set_h225_addr = rcu_dereference(set_h225_addr_hook);
if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
- (set_h225_addr) && ct->status & IPS_NAT_MASK &&
+ (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK &&
get_h225_addr(ct, *data, &setup->destCallSignalAddress,
&addr, &port) &&
memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) {
@@ -868,7 +873,8 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
}
if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
- (set_h225_addr) && ct->status & IPS_NAT_MASK &&
+ (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK &&
get_h225_addr(ct, *data, &setup->sourceCallSignalAddress,
&addr, &port) &&
memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) {
@@ -1278,7 +1284,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
nat_q931 = rcu_dereference(nat_q931_hook);
- if (nat_q931 && ct->status & IPS_NAT_MASK) { /* Need NAT */
+ if (nat_q931 && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) { /* Need NAT */
ret = nat_q931(skb, ct, ctinfo, data, taddr, i, port, exp);
} else { /* Conntrack only */
if (nf_ct_expect_related(exp) == 0) {
@@ -1306,7 +1313,8 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
pr_debug("nf_ct_ras: GRQ\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr && ct->status & IPS_NAT_MASK) /* NATed */
+ if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) /* NATed */
return set_ras_addr(skb, ct, ctinfo, data,
&grq->rasAddress, 1);
return 0;
@@ -1374,7 +1382,8 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
return -1;
set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr && ct->status & IPS_NAT_MASK) {
+ if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
ret = set_ras_addr(skb, ct, ctinfo, data,
rrq->rasAddress.item,
rrq->rasAddress.count);
@@ -1405,7 +1414,8 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
pr_debug("nf_ct_ras: RCF\n");
set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr && ct->status & IPS_NAT_MASK) {
+ if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
ret = set_sig_addr(skb, ct, ctinfo, data,
rcf->callSignalAddress.item,
rcf->callSignalAddress.count);
@@ -1453,7 +1463,8 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
pr_debug("nf_ct_ras: URQ\n");
set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr && ct->status & IPS_NAT_MASK) {
+ if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
ret = set_sig_addr(skb, ct, ctinfo, data,
urq->callSignalAddress.item,
urq->callSignalAddress.count);
@@ -1491,6 +1502,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
&addr, &port) &&
!memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
port == info->sig_port[dir] &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 &&
set_h225_addr && ct->status & IPS_NAT_MASK) {
/* Answering ARQ */
return set_h225_addr(skb, data, 0,
@@ -1503,7 +1515,8 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
get_h225_addr(ct, *data, &arq->srcCallSignalAddress,
&addr, &port) &&
!memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
- set_h225_addr && ct->status & IPS_NAT_MASK) {
+ set_h225_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
/* Calling ARQ */
return set_h225_addr(skb, data, 0,
&arq->srcCallSignalAddress,
@@ -1535,7 +1548,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
if (!memcmp(&addr, &ct->tuplehash[dir].tuple.dst.u3, sizeof(addr))) {
/* Answering ACF */
set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr && ct->status & IPS_NAT_MASK)
+ if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
return set_sig_addr(skb, ct, ctinfo, data,
&acf->destCallSignalAddress, 1);
return 0;
@@ -1571,7 +1585,8 @@ static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
pr_debug("nf_ct_ras: LRQ\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr && ct->status & IPS_NAT_MASK)
+ if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
return set_ras_addr(skb, ct, ctinfo, data,
&lrq->replyAddress, 1);
return 0;
@@ -1628,7 +1643,8 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
pr_debug("nf_ct_ras: IRR\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr && ct->status & IPS_NAT_MASK) {
+ if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
ret = set_ras_addr(skb, ct, ctinfo, data,
&irr->rasAddress, 1);
if (ret < 0)
@@ -1636,7 +1652,8 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
}
set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr && ct->status & IPS_NAT_MASK) {
+ if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
ret = set_sig_addr(skb, ct, ctinfo, data,
irr->callSignalAddress.item,
irr->callSignalAddress.count);
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 009c52c..e06dc2f 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -204,7 +204,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
IPPROTO_TCP, NULL, &port);
nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
- if (nf_nat_irc && ct->status & IPS_NAT_MASK)
+ if (nf_nat_irc && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_irc(skb, ctinfo,
addr_beg_p - ib_ptr,
addr_end_p - addr_beg_p,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 5c0a112..d08e0ba 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -981,7 +981,8 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff,
IPPROTO_UDP, NULL, &rtcp_port);
nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
- if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
+ if (nf_nat_sdp_media && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK && !direct_rtp)
ret = nf_nat_sdp_media(skb, dataoff, dptr, datalen,
rtp_exp, rtcp_exp,
mediaoff, medialen, daddr);
@@ -1104,7 +1105,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff,
return ret;
/* Update media connection address if present */
- if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+ if (maddr_len && nf_nat_sdp_addr &&
+ nf_ct_l3num(ct) == NFPROTO_IPV4 && ct->status & IPS_NAT_MASK) {
ret = nf_nat_sdp_addr(skb, dataoff, dptr, datalen,
mediaoff, c_hdr, SDP_HDR_MEDIA,
&rtp_addr);
@@ -1116,7 +1118,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff,
/* Update session connection and owner addresses */
nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
- if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
+ if (nf_nat_sdp_session && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_sdp_session(skb, dataoff, dptr, datalen, sdpoff,
&rtp_addr);
@@ -1275,7 +1278,8 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff,
exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
- if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
+ if (nf_nat_sip_expect && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_sip_expect(skb, dataoff, dptr, datalen, exp,
matchoff, matchlen);
else {
@@ -1453,7 +1457,8 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
else
ret = process_sip_response(skb, dataoff, dptr, datalen);
- if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+ if (ret == NF_ACCEPT && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
if (nf_nat_sip && !nf_nat_sip(skb, dataoff, dptr, datalen))
ret = NF_DROP;
@@ -1534,7 +1539,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
datalen = datalen + diff - msglen;
}
- if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+ if (ret == NF_ACCEPT && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK) {
nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook);
if (nf_nat_sip_seq_adjust)
nf_nat_sip_seq_adjust(skb, tdiff);
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index 81fc61c..9363e1c 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -72,7 +72,8 @@ static int tftp_help(struct sk_buff *skb,
nf_ct_dump_tuple(&exp->tuple);
nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
- if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
+ if (nf_nat_tftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+ ct->status & IPS_NAT_MASK)
ret = nf_nat_tftp(skb, ctinfo, exp);
else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
--
1.7.1
^ permalink raw reply related
* [PATCH 09/19] net: core: add function for incremental IPv6 pseudo header checksum updates
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
Add inet_proto_csum_replace16 for incrementally updating IPv6 pseudo header
checksums for IPv6 NAT.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Acked-by: David S. Miller <davem@davemloft.net>
---
include/net/checksum.h | 3 +++
net/core/utils.c | 20 ++++++++++++++++++++
2 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/include/net/checksum.h b/include/net/checksum.h
index ba55d8b..600d1d7 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -109,6 +109,9 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
struct sk_buff;
extern void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
__be32 from, __be32 to, int pseudohdr);
+extern void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+ const __be32 *from, const __be32 *to,
+ int pseudohdr);
static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
__be16 from, __be16 to,
diff --git a/net/core/utils.c b/net/core/utils.c
index 39895a6..f5613d5 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -294,6 +294,26 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
}
EXPORT_SYMBOL(inet_proto_csum_replace4);
+void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+ const __be32 *from, const __be32 *to,
+ int pseudohdr)
+{
+ __be32 diff[] = {
+ ~from[0], ~from[1], ~from[2], ~from[3],
+ to[0], to[1], to[2], to[3],
+ };
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ *sum = csum_fold(csum_partial(diff, sizeof(diff),
+ ~csum_unfold(*sum)));
+ if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+ skb->csum = ~csum_partial(diff, sizeof(diff),
+ ~skb->csum);
+ } else if (pseudohdr)
+ *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+ csum_unfold(*sum)));
+}
+EXPORT_SYMBOL(inet_proto_csum_replace16);
+
int mac_pton(const char *s, u8 *mac)
{
int i;
--
1.7.1
^ permalink raw reply related
* [PATCH 12/19] netfilter: ip6tables: add REDIRECT target
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
net/ipv6/netfilter/Kconfig | 11 ++++
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_REDIRECT.c | 98 ++++++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 net/ipv6/netfilter/ip6t_REDIRECT.c
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 54a5032..585590f 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -156,6 +156,17 @@ config IP6_NF_TARGET_MASQUERADE
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_TARGET_REDIRECT
+ tristate "REDIRECT target support"
+ depends on NF_NAT_IPV6
+ help
+ REDIRECT is a special case of NAT: all incoming connections are
+ mapped onto the incoming interface's address, causing the packets to
+ come to the local machine instead of passing through. This is
+ useful for transparent proxies.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_FILTER
tristate "Packet filtering"
default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 068bad1..e30a531 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -35,4 +35,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
+obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
diff --git a/net/ipv6/netfilter/ip6t_REDIRECT.c b/net/ipv6/netfilter/ip6t_REDIRECT.c
new file mode 100644
index 0000000..60497a3
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_REDIRECT.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6
+ * NAT funded by Astaro.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/x_tables.h>
+#include <net/addrconf.h>
+#include <net/netfilter/nf_nat.h>
+
+static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
+
+static unsigned int
+redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct nf_nat_range *range = par->targinfo;
+ struct nf_nat_range newrange;
+ struct in6_addr newdst;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (par->hooknum == NF_INET_LOCAL_OUT)
+ newdst = loopback_addr;
+ else {
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifa;
+ bool addr = false;
+
+ rcu_read_lock();
+ idev = __in6_dev_get(skb->dev);
+ if (idev != NULL) {
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ newdst = ifa->addr;
+ addr = true;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!addr)
+ return NF_DROP;
+ }
+
+ newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
+ newrange.min_addr.in6 = newdst;
+ newrange.max_addr.in6 = newdst;
+ newrange.min_proto = range->min_proto;
+ newrange.max_proto = range->max_proto;
+
+ return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
+}
+
+static int redirect_tg6_checkentry(const struct xt_tgchk_param *par)
+{
+ const struct nf_nat_range *range = par->targinfo;
+
+ if (range->flags & NF_NAT_RANGE_MAP_IPS)
+ return -EINVAL;
+ return 0;
+}
+
+static struct xt_target redirect_tg6_reg __read_mostly = {
+ .name = "REDIRECT",
+ .family = NFPROTO_IPV6,
+ .checkentry = redirect_tg6_checkentry,
+ .target = redirect_tg6,
+ .targetsize = sizeof(struct nf_nat_range),
+ .table = "nat",
+ .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
+ .me = THIS_MODULE,
+};
+
+static int __init redirect_tg6_init(void)
+{
+ return xt_register_target(&redirect_tg6_reg);
+}
+
+static void __exit redirect_tg6_exit(void)
+{
+ xt_unregister_target(&redirect_tg6_reg);
+}
+
+module_init(redirect_tg6_init);
+module_exit(redirect_tg6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
--
1.7.1
^ permalink raw reply related
* [PATCH 19/19] netfilter: ip6tables: add stateless IPv6-to-IPv6 Network Prefix Translation target
From: Patrick McHardy @ 2012-08-28 21:48 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1346190539-9963-1-git-send-email-kaber@trash.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/linux/netfilter_ipv6/Kbuild | 1 +
include/linux/netfilter_ipv6/ip6t_NPT.h | 16 +++
net/ipv6/netfilter/Kconfig | 9 ++
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_NPT.c | 165 +++++++++++++++++++++++++++++++
5 files changed, 192 insertions(+), 0 deletions(-)
create mode 100644 include/linux/netfilter_ipv6/ip6t_NPT.h
create mode 100644 net/ipv6/netfilter/ip6t_NPT.c
diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild
index bd095bc..b88c005 100644
--- a/include/linux/netfilter_ipv6/Kbuild
+++ b/include/linux/netfilter_ipv6/Kbuild
@@ -1,6 +1,7 @@
header-y += ip6_tables.h
header-y += ip6t_HL.h
header-y += ip6t_LOG.h
+header-y += ip6t_NPT.h
header-y += ip6t_REJECT.h
header-y += ip6t_ah.h
header-y += ip6t_frag.h
diff --git a/include/linux/netfilter_ipv6/ip6t_NPT.h b/include/linux/netfilter_ipv6/ip6t_NPT.h
new file mode 100644
index 0000000..f763355
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_NPT.h
@@ -0,0 +1,16 @@
+#ifndef __NETFILTER_IP6T_NPT
+#define __NETFILTER_IP6T_NPT
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+struct ip6t_npt_tginfo {
+ union nf_inet_addr src_pfx;
+ union nf_inet_addr dst_pfx;
+ __u8 src_pfx_len;
+ __u8 dst_pfx_len;
+ /* Used internally by the kernel */
+ __sum16 adjustment;
+};
+
+#endif /* __NETFILTER_IP6T_NPT */
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 7bdf73b..3b73254 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -177,6 +177,15 @@ config IP6_NF_TARGET_REDIRECT
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_TARGET_NPT
+ tristate "NPT (Network Prefix translation) target support"
+ depends on NETFILTER_ADVANCED
+ help
+ This option adds the `SNPT' and `DNPT' target, which perform
+ stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_FILTER
tristate "Packet filtering"
default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 0864ce6..5752132 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -36,5 +36,6 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
obj-$(CONFIG_IP6_NF_TARGET_NETMAP) += ip6t_NETMAP.o
+obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
new file mode 100644
index 0000000..e948691
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011, 2012 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_ipv6/ip6t_NPT.h>
+#include <linux/netfilter/x_tables.h>
+
+static __sum16 csum16_complement(__sum16 a)
+{
+ return (__force __sum16)(0xffff - (__force u16)a);
+}
+
+static __sum16 csum16_add(__sum16 a, __sum16 b)
+{
+ u16 sum;
+
+ sum = (__force u16)a + (__force u16)b;
+ sum += (__force u16)a < (__force u16)b;
+ return (__force __sum16)sum;
+}
+
+static __sum16 csum16_sub(__sum16 a, __sum16 b)
+{
+ return csum16_add(a, csum16_complement(b));
+}
+
+static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
+{
+ struct ip6t_npt_tginfo *npt = par->targinfo;
+ __sum16 src_sum = 0, dst_sum = 0;
+ unsigned int i;
+
+ if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) {
+ src_sum = csum16_add(src_sum,
+ (__force __sum16)npt->src_pfx.in6.s6_addr16[i]);
+ dst_sum = csum16_add(dst_sum,
+ (__force __sum16)npt->dst_pfx.in6.s6_addr16[i]);
+ }
+
+ npt->adjustment = csum16_sub(src_sum, dst_sum);
+ return 0;
+}
+
+static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
+ struct in6_addr *addr)
+{
+ unsigned int pfx_len;
+ unsigned int i, idx;
+ __be32 mask;
+ __sum16 sum;
+
+ pfx_len = max(npt->src_pfx_len, npt->dst_pfx_len);
+ for (i = 0; i < pfx_len; i += 32) {
+ if (pfx_len - i >= 32)
+ mask = 0;
+ else
+ mask = htonl(~((1 << (pfx_len - i)) - 1));
+
+ idx = i / 32;
+ addr->s6_addr32[idx] &= mask;
+ addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx];
+ }
+
+ if (pfx_len <= 48)
+ idx = 3;
+ else {
+ for (idx = 4; idx < ARRAY_SIZE(addr->s6_addr16); idx++) {
+ if ((__force __sum16)addr->s6_addr16[idx] !=
+ CSUM_MANGLED_0)
+ break;
+ }
+ if (idx == ARRAY_SIZE(addr->s6_addr16))
+ return false;
+ }
+
+ sum = csum16_add((__force __sum16)addr->s6_addr16[idx],
+ npt->adjustment);
+ if (sum == CSUM_MANGLED_0)
+ sum = 0;
+ *(__force __sum16 *)&addr->s6_addr16[idx] = sum;
+
+ return true;
+}
+
+static unsigned int
+ip6t_snpt_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct ip6t_npt_tginfo *npt = par->targinfo;
+
+ if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->saddr)) {
+ icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD,
+ offsetof(struct ipv6hdr, saddr));
+ return NF_DROP;
+ }
+ return XT_CONTINUE;
+}
+
+static unsigned int
+ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct ip6t_npt_tginfo *npt = par->targinfo;
+
+ if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->daddr)) {
+ icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD,
+ offsetof(struct ipv6hdr, daddr));
+ return NF_DROP;
+ }
+ return XT_CONTINUE;
+}
+
+static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
+ {
+ .name = "SNPT",
+ .target = ip6t_snpt_tg,
+ .targetsize = sizeof(struct ip6t_npt_tginfo),
+ .checkentry = ip6t_npt_checkentry,
+ .family = NFPROTO_IPV6,
+ .hooks = (1 << NF_INET_LOCAL_IN) |
+ (1 << NF_INET_POST_ROUTING),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "DNPT",
+ .target = ip6t_dnpt_tg,
+ .targetsize = sizeof(struct ip6t_npt_tginfo),
+ .checkentry = ip6t_npt_checkentry,
+ .family = NFPROTO_IPV6,
+ .hooks = (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_OUT),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init ip6t_npt_init(void)
+{
+ return xt_register_targets(ip6t_npt_target_reg,
+ ARRAY_SIZE(ip6t_npt_target_reg));
+}
+
+static void __exit ip6t_npt_exit(void)
+{
+ xt_unregister_targets(ip6t_npt_target_reg,
+ ARRAY_SIZE(ip6t_npt_target_reg));
+}
+
+module_init(ip6t_npt_init);
+module_exit(ip6t_npt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6-to-IPv6 Network Prefix Translation (RFC 6296)");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS("ip6t_SNPT");
+MODULE_ALIAS("ip6t_DNPT");
--
1.7.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox