aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/cpm2.c
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@gmail.com>2008-04-02 16:04:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-02 18:28:19 -0400
commitffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4c (patch)
tree465f41f6c4e0e63c58a94c893d0b4ec5c5e7a10d /arch/powerpc/sysdev/cpm2.c
parentf2b2ea692ec01768c77a4f532dcd060316460122 (diff)
nbd: prevent sock_xmit from attempting to use a NULL socket
NBD does not protect the nbd_device's socket from becoming NULL during receives. This closes a race with the NBD_CLEAR_SOCK ioctl (nbd-client -d) setting the nbd_device's socket to NULL right before NBD calls sock_xmit. Signed-off-by: Mike Snitzer <snitzer@gmail.com> Cc: Paul Clements <paul.clements@steeleye.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/powerpc/sysdev/cpm2.c')
0 files changed, 0 insertions, 0 deletions
>
e552b6617067











e552b6617067
fb78922ce9c7
0eea10301708









e552b6617067

0eea10301708
e552b6617067





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145











                                             
                       





                                                  
                                                       









                                                                             

                                                    































                                                                                

                                                           



                                       

                                           










                                                                 

                                                                           
 
                                



                                                  



                                                



                                                                      




                                                                 
                                                                  

                                                                             


                        

                                     











                                                 
 
                      









                                                     

                                                  
                                                      





                     
/*
 * resource cgroups
 *
 * Copyright 2007 OpenVZ SWsoft Inc
 *
 * Author: Pavel Emelianov <xemul@openvz.org>
 *
 */

#include <linux/types.h>
#include <linux/parser.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/res_counter.h>
#include <linux/uaccess.h>

void res_counter_init(struct res_counter *counter)
{
	spin_lock_init(&counter->lock);
	counter->limit = (unsigned long long)LLONG_MAX;
}

int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
{
	if (counter->usage + val > counter->limit) {
		counter->failcnt++;
		return -ENOMEM;
	}

	counter->usage += val;
	if (counter->usage > counter->max_usage)
		counter->max_usage = counter->usage;
	return 0;
}

int res_counter_charge(struct res_counter *counter, unsigned long val)
{
	int ret;
	unsigned long flags;

	spin_lock_irqsave(&counter->lock, flags);
	ret = res_counter_charge_locked(counter, val);
	spin_unlock_irqrestore(&counter->lock, flags);
	return ret;
}

void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
{
	if (WARN_ON(counter->usage < val))
		val = counter->usage;

	counter->usage -= val;
}

void res_counter_uncharge(struct res_counter *counter, unsigned long val)
{
	unsigned long flags;

	spin_lock_irqsave(&counter->lock, flags);
	res_counter_uncharge_locked(counter, val);
	spin_unlock_irqrestore(&counter->lock, flags);
}


static inline unsigned long long *
res_counter_member(struct res_counter *counter, int member)
{
	switch (member) {
	case RES_USAGE:
		return &counter->usage;
	case RES_MAX_USAGE:
		return &counter->max_usage;
	case RES_LIMIT:
		return &counter->limit;
	case RES_FAILCNT:
		return &counter->failcnt;
	};

	BUG();
	return NULL;
}

ssize_t res_counter_read(struct res_counter *counter, int member,
		const char __user *userbuf, size_t nbytes, loff_t *pos,
		int (*read_strategy)(unsigned long long val, char *st_buf))
{
	unsigned long long *val;
	char buf[64], *s;

	s = buf;
	val = res_counter_member(counter, member);
	if (read_strategy)
		s += read_strategy(*val, s);
	else
		s += sprintf(s, "%llu\n", *val);
	return simple_read_from_buffer((void __user *)userbuf, nbytes,
			pos, buf, s - buf);
}

u64 res_counter_read_u64(struct res_counter *counter, int member)
{
	return *res_counter_member(counter, member);
}

ssize_t res_counter_write(struct res_counter *counter, int member,
		const char __user *userbuf, size_t nbytes, loff_t *pos,
		int (*write_strategy)(char *st_buf, unsigned long long *val))
{
	int ret;
	char *buf, *end;
	unsigned long flags;
	unsigned long long tmp, *val;

	buf = kmalloc(nbytes + 1, GFP_KERNEL);
	ret = -ENOMEM;
	if (buf == NULL)
		goto out;

	buf[nbytes] = '\0';
	ret = -EFAULT;
	if (copy_from_user(buf, userbuf, nbytes))
		goto out_free;

	ret = -EINVAL;

	strstrip(buf);
	if (write_strategy) {
		if (write_strategy(buf, &tmp)) {
			goto out_free;
		}
	} else {
		tmp = simple_strtoull(buf, &end, 10);
		if (*end != '\0')
			goto out_free;
	}
	spin_lock_irqsave(&counter->lock, flags);
	val = res_counter_member(counter, member);
	*val = tmp;
	spin_unlock_irqrestore(&counter->lock, flags);
	ret = nbytes;
out_free:
	kfree(buf);
out:
	return ret;
}