Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1674 commits) qlcnic: adding co maintainer ixgbe: add support for active DA cables ixgbe: dcb, do not tag tc_prio_control frames ixgbe: fix ixgbe_tx_is_paused logic ixgbe: always enable vlan strip/insert when DCB is enabled ixgbe: remove some redundant code in setting FCoE FIP filter ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp ixgbe: fix header len when unsplit packet overflows to data buffer ipv6: Never schedule DAD timer on dead address ipv6: Use POSTDAD state ipv6: Use state_lock to protect ifa state ipv6: Replace inet6_ifaddr->dead with state cxgb4: notify upper drivers if the device is already up when they load cxgb4: keep interrupts available when the ports are brought down cxgb4: fix initial addition of MAC address cnic: Return SPQ credit to bnx2x after ring setup and shutdown. cnic: Convert cnic_local_flags to atomic ops. can: Fix SJA1000 command register writes on SMP systems bridge: fix build for CONFIG_SYSFS disabled ARCNET: Limit com20020 PCI ID matches for SOHARD cards ... Fix up various conflicts with pcmcia tree drivers/net/ {pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and wireless/orinoco/spectrum_cs.c} and feature removal (Documentation/feature-removal-schedule.txt). Also fix a non-content conflict due to pm_qos_requirement getting renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c
This commit is contained in:
569
kernel/sysctl.c
569
kernel/sysctl.c
@@ -2062,8 +2062,132 @@ int proc_dostring(struct ctl_table *table, int write,
|
||||
buffer, lenp, ppos);
|
||||
}
|
||||
|
||||
static size_t proc_skip_spaces(char **buf)
|
||||
{
|
||||
size_t ret;
|
||||
char *tmp = skip_spaces(*buf);
|
||||
ret = tmp - *buf;
|
||||
*buf = tmp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
|
||||
static void proc_skip_char(char **buf, size_t *size, const char v)
|
||||
{
|
||||
while (*size) {
|
||||
if (**buf != v)
|
||||
break;
|
||||
(*size)--;
|
||||
(*buf)++;
|
||||
}
|
||||
}
|
||||
|
||||
#define TMPBUFLEN 22
|
||||
/**
|
||||
* proc_get_long - reads an ASCII formated integer from a user buffer
|
||||
*
|
||||
* @buf - a kernel buffer
|
||||
* @size - size of the kernel buffer
|
||||
* @val - this is where the number will be stored
|
||||
* @neg - set to %TRUE if number is negative
|
||||
* @perm_tr - a vector which contains the allowed trailers
|
||||
* @perm_tr_len - size of the perm_tr vector
|
||||
* @tr - pointer to store the trailer character
|
||||
*
|
||||
* In case of success 0 is returned and buf and size are updated with
|
||||
* the amount of bytes read. If tr is non NULL and a trailing
|
||||
* character exist (size is non zero after returning from this
|
||||
* function) tr is updated with the trailing character.
|
||||
*/
|
||||
static int proc_get_long(char **buf, size_t *size,
|
||||
unsigned long *val, bool *neg,
|
||||
const char *perm_tr, unsigned perm_tr_len, char *tr)
|
||||
{
|
||||
int len;
|
||||
char *p, tmp[TMPBUFLEN];
|
||||
|
||||
if (!*size)
|
||||
return -EINVAL;
|
||||
|
||||
len = *size;
|
||||
if (len > TMPBUFLEN - 1)
|
||||
len = TMPBUFLEN - 1;
|
||||
|
||||
memcpy(tmp, *buf, len);
|
||||
|
||||
tmp[len] = 0;
|
||||
p = tmp;
|
||||
if (*p == '-' && *size > 1) {
|
||||
*neg = true;
|
||||
p++;
|
||||
} else
|
||||
*neg = false;
|
||||
if (!isdigit(*p))
|
||||
return -EINVAL;
|
||||
|
||||
*val = simple_strtoul(p, &p, 0);
|
||||
|
||||
len = p - tmp;
|
||||
|
||||
/* We don't know if the next char is whitespace thus we may accept
|
||||
* invalid integers (e.g. 1234...a) or two integers instead of one
|
||||
* (e.g. 123...1). So lets not allow such large numbers. */
|
||||
if (len == TMPBUFLEN - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len))
|
||||
return -EINVAL;
|
||||
|
||||
if (tr && (len < *size))
|
||||
*tr = *p;
|
||||
|
||||
*buf += len;
|
||||
*size -= len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* proc_put_long - coverts an integer to a decimal ASCII formated string
|
||||
*
|
||||
* @buf - the user buffer
|
||||
* @size - the size of the user buffer
|
||||
* @val - the integer to be converted
|
||||
* @neg - sign of the number, %TRUE for negative
|
||||
*
|
||||
* In case of success 0 is returned and buf and size are updated with
|
||||
* the amount of bytes read.
|
||||
*/
|
||||
static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
|
||||
bool neg)
|
||||
{
|
||||
int len;
|
||||
char tmp[TMPBUFLEN], *p = tmp;
|
||||
|
||||
sprintf(p, "%s%lu", neg ? "-" : "", val);
|
||||
len = strlen(tmp);
|
||||
if (len > *size)
|
||||
len = *size;
|
||||
if (copy_to_user(*buf, tmp, len))
|
||||
return -EFAULT;
|
||||
*size -= len;
|
||||
*buf += len;
|
||||
return 0;
|
||||
}
|
||||
#undef TMPBUFLEN
|
||||
|
||||
static int proc_put_char(void __user **buf, size_t *size, char c)
|
||||
{
|
||||
if (*size) {
|
||||
char __user **buffer = (char __user **)buf;
|
||||
if (put_user(c, *buffer))
|
||||
return -EFAULT;
|
||||
(*size)--, (*buffer)++;
|
||||
*buf = *buffer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
int write, void *data)
|
||||
{
|
||||
@@ -2072,33 +2196,31 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
|
||||
} else {
|
||||
int val = *valp;
|
||||
if (val < 0) {
|
||||
*negp = -1;
|
||||
*negp = true;
|
||||
*lvalp = (unsigned long)-val;
|
||||
} else {
|
||||
*negp = 0;
|
||||
*negp = false;
|
||||
*lvalp = (unsigned long)val;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
|
||||
|
||||
static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
|
||||
int write, void __user *buffer,
|
||||
size_t *lenp, loff_t *ppos,
|
||||
int (*conv)(int *negp, unsigned long *lvalp, int *valp,
|
||||
int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
|
||||
int write, void *data),
|
||||
void *data)
|
||||
{
|
||||
#define TMPBUFLEN 21
|
||||
int *i, vleft, first = 1, neg;
|
||||
unsigned long lval;
|
||||
size_t left, len;
|
||||
int *i, vleft, first = 1, err = 0;
|
||||
unsigned long page = 0;
|
||||
size_t left;
|
||||
char *kbuf;
|
||||
|
||||
char buf[TMPBUFLEN], *p;
|
||||
char __user *s = buffer;
|
||||
|
||||
if (!tbl_data || !table->maxlen || !*lenp ||
|
||||
(*ppos && !write)) {
|
||||
if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -2110,89 +2232,69 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
|
||||
if (!conv)
|
||||
conv = do_proc_dointvec_conv;
|
||||
|
||||
for (; left && vleft--; i++, first=0) {
|
||||
if (write) {
|
||||
while (left) {
|
||||
char c;
|
||||
if (get_user(c, s))
|
||||
return -EFAULT;
|
||||
if (!isspace(c))
|
||||
break;
|
||||
left--;
|
||||
s++;
|
||||
}
|
||||
if (!left)
|
||||
break;
|
||||
neg = 0;
|
||||
len = left;
|
||||
if (len > sizeof(buf) - 1)
|
||||
len = sizeof(buf) - 1;
|
||||
if (copy_from_user(buf, s, len))
|
||||
return -EFAULT;
|
||||
buf[len] = 0;
|
||||
p = buf;
|
||||
if (*p == '-' && left > 1) {
|
||||
neg = 1;
|
||||
p++;
|
||||
}
|
||||
if (*p < '0' || *p > '9')
|
||||
break;
|
||||
|
||||
lval = simple_strtoul(p, &p, 0);
|
||||
|
||||
len = p-buf;
|
||||
if ((len < left) && *p && !isspace(*p))
|
||||
break;
|
||||
s += len;
|
||||
left -= len;
|
||||
|
||||
if (conv(&neg, &lval, i, 1, data))
|
||||
break;
|
||||
} else {
|
||||
p = buf;
|
||||
if (!first)
|
||||
*p++ = '\t';
|
||||
|
||||
if (conv(&neg, &lval, i, 0, data))
|
||||
break;
|
||||
|
||||
sprintf(p, "%s%lu", neg ? "-" : "", lval);
|
||||
len = strlen(buf);
|
||||
if (len > left)
|
||||
len = left;
|
||||
if(copy_to_user(s, buf, len))
|
||||
return -EFAULT;
|
||||
left -= len;
|
||||
s += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (!write && !first && left) {
|
||||
if(put_user('\n', s))
|
||||
return -EFAULT;
|
||||
left--, s++;
|
||||
}
|
||||
if (write) {
|
||||
while (left) {
|
||||
char c;
|
||||
if (get_user(c, s++))
|
||||
return -EFAULT;
|
||||
if (!isspace(c))
|
||||
if (left > PAGE_SIZE - 1)
|
||||
left = PAGE_SIZE - 1;
|
||||
page = __get_free_page(GFP_TEMPORARY);
|
||||
kbuf = (char *) page;
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kbuf, buffer, left)) {
|
||||
err = -EFAULT;
|
||||
goto free;
|
||||
}
|
||||
kbuf[left] = 0;
|
||||
}
|
||||
|
||||
for (; left && vleft--; i++, first=0) {
|
||||
unsigned long lval;
|
||||
bool neg;
|
||||
|
||||
if (write) {
|
||||
left -= proc_skip_spaces(&kbuf);
|
||||
|
||||
err = proc_get_long(&kbuf, &left, &lval, &neg,
|
||||
proc_wspace_sep,
|
||||
sizeof(proc_wspace_sep), NULL);
|
||||
if (err)
|
||||
break;
|
||||
if (conv(&neg, &lval, i, 1, data)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (conv(&neg, &lval, i, 0, data)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!first)
|
||||
err = proc_put_char(&buffer, &left, '\t');
|
||||
if (err)
|
||||
break;
|
||||
err = proc_put_long(&buffer, &left, lval, neg);
|
||||
if (err)
|
||||
break;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
if (write && first)
|
||||
return -EINVAL;
|
||||
|
||||
if (!write && !first && left && !err)
|
||||
err = proc_put_char(&buffer, &left, '\n');
|
||||
if (write && !err)
|
||||
left -= proc_skip_spaces(&kbuf);
|
||||
free:
|
||||
if (write) {
|
||||
free_page(page);
|
||||
if (first)
|
||||
return err ? : -EINVAL;
|
||||
}
|
||||
*lenp -= left;
|
||||
*ppos += *lenp;
|
||||
return 0;
|
||||
#undef TMPBUFLEN
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_proc_dointvec(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos,
|
||||
int (*conv)(int *negp, unsigned long *lvalp, int *valp,
|
||||
int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
|
||||
int write, void *data),
|
||||
void *data)
|
||||
{
|
||||
@@ -2260,8 +2362,8 @@ struct do_proc_dointvec_minmax_conv_param {
|
||||
int *max;
|
||||
};
|
||||
|
||||
static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
int write, void *data)
|
||||
{
|
||||
struct do_proc_dointvec_minmax_conv_param *param = data;
|
||||
@@ -2274,10 +2376,10 @@ static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp,
|
||||
} else {
|
||||
int val = *valp;
|
||||
if (val < 0) {
|
||||
*negp = -1;
|
||||
*negp = true;
|
||||
*lvalp = (unsigned long)-val;
|
||||
} else {
|
||||
*negp = 0;
|
||||
*negp = false;
|
||||
*lvalp = (unsigned long)val;
|
||||
}
|
||||
}
|
||||
@@ -2317,102 +2419,78 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
|
||||
unsigned long convmul,
|
||||
unsigned long convdiv)
|
||||
{
|
||||
#define TMPBUFLEN 21
|
||||
unsigned long *i, *min, *max, val;
|
||||
int vleft, first=1, neg;
|
||||
size_t len, left;
|
||||
char buf[TMPBUFLEN], *p;
|
||||
char __user *s = buffer;
|
||||
|
||||
if (!data || !table->maxlen || !*lenp ||
|
||||
(*ppos && !write)) {
|
||||
unsigned long *i, *min, *max;
|
||||
int vleft, first = 1, err = 0;
|
||||
unsigned long page = 0;
|
||||
size_t left;
|
||||
char *kbuf;
|
||||
|
||||
if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
i = (unsigned long *) data;
|
||||
min = (unsigned long *) table->extra1;
|
||||
max = (unsigned long *) table->extra2;
|
||||
vleft = table->maxlen / sizeof(unsigned long);
|
||||
left = *lenp;
|
||||
|
||||
|
||||
if (write) {
|
||||
if (left > PAGE_SIZE - 1)
|
||||
left = PAGE_SIZE - 1;
|
||||
page = __get_free_page(GFP_TEMPORARY);
|
||||
kbuf = (char *) page;
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kbuf, buffer, left)) {
|
||||
err = -EFAULT;
|
||||
goto free;
|
||||
}
|
||||
kbuf[left] = 0;
|
||||
}
|
||||
|
||||
for (; left && vleft--; i++, min++, max++, first=0) {
|
||||
unsigned long val;
|
||||
|
||||
if (write) {
|
||||
while (left) {
|
||||
char c;
|
||||
if (get_user(c, s))
|
||||
return -EFAULT;
|
||||
if (!isspace(c))
|
||||
break;
|
||||
left--;
|
||||
s++;
|
||||
}
|
||||
if (!left)
|
||||
break;
|
||||
neg = 0;
|
||||
len = left;
|
||||
if (len > TMPBUFLEN-1)
|
||||
len = TMPBUFLEN-1;
|
||||
if (copy_from_user(buf, s, len))
|
||||
return -EFAULT;
|
||||
buf[len] = 0;
|
||||
p = buf;
|
||||
if (*p == '-' && left > 1) {
|
||||
neg = 1;
|
||||
p++;
|
||||
}
|
||||
if (*p < '0' || *p > '9')
|
||||
break;
|
||||
val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
|
||||
len = p-buf;
|
||||
if ((len < left) && *p && !isspace(*p))
|
||||
bool neg;
|
||||
|
||||
left -= proc_skip_spaces(&kbuf);
|
||||
|
||||
err = proc_get_long(&kbuf, &left, &val, &neg,
|
||||
proc_wspace_sep,
|
||||
sizeof(proc_wspace_sep), NULL);
|
||||
if (err)
|
||||
break;
|
||||
if (neg)
|
||||
val = -val;
|
||||
s += len;
|
||||
left -= len;
|
||||
|
||||
if(neg)
|
||||
continue;
|
||||
if ((min && val < *min) || (max && val > *max))
|
||||
continue;
|
||||
*i = val;
|
||||
} else {
|
||||
p = buf;
|
||||
val = convdiv * (*i) / convmul;
|
||||
if (!first)
|
||||
*p++ = '\t';
|
||||
sprintf(p, "%lu", convdiv * (*i) / convmul);
|
||||
len = strlen(buf);
|
||||
if (len > left)
|
||||
len = left;
|
||||
if(copy_to_user(s, buf, len))
|
||||
return -EFAULT;
|
||||
left -= len;
|
||||
s += len;
|
||||
err = proc_put_char(&buffer, &left, '\t');
|
||||
err = proc_put_long(&buffer, &left, val, false);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!write && !first && left) {
|
||||
if(put_user('\n', s))
|
||||
return -EFAULT;
|
||||
left--, s++;
|
||||
}
|
||||
if (!write && !first && left && !err)
|
||||
err = proc_put_char(&buffer, &left, '\n');
|
||||
if (write && !err)
|
||||
left -= proc_skip_spaces(&kbuf);
|
||||
free:
|
||||
if (write) {
|
||||
while (left) {
|
||||
char c;
|
||||
if (get_user(c, s++))
|
||||
return -EFAULT;
|
||||
if (!isspace(c))
|
||||
break;
|
||||
left--;
|
||||
}
|
||||
free_page(page);
|
||||
if (first)
|
||||
return err ? : -EINVAL;
|
||||
}
|
||||
if (write && first)
|
||||
return -EINVAL;
|
||||
*lenp -= left;
|
||||
*ppos += *lenp;
|
||||
return 0;
|
||||
#undef TMPBUFLEN
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_proc_doulongvec_minmax(struct ctl_table *table, int write,
|
||||
@@ -2473,7 +2551,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
|
||||
}
|
||||
|
||||
|
||||
static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
int write, void *data)
|
||||
{
|
||||
@@ -2485,10 +2563,10 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
int val = *valp;
|
||||
unsigned long lval;
|
||||
if (val < 0) {
|
||||
*negp = -1;
|
||||
*negp = true;
|
||||
lval = (unsigned long)-val;
|
||||
} else {
|
||||
*negp = 0;
|
||||
*negp = false;
|
||||
lval = (unsigned long)val;
|
||||
}
|
||||
*lvalp = lval / HZ;
|
||||
@@ -2496,7 +2574,7 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
int write, void *data)
|
||||
{
|
||||
@@ -2508,10 +2586,10 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
int val = *valp;
|
||||
unsigned long lval;
|
||||
if (val < 0) {
|
||||
*negp = -1;
|
||||
*negp = true;
|
||||
lval = (unsigned long)-val;
|
||||
} else {
|
||||
*negp = 0;
|
||||
*negp = false;
|
||||
lval = (unsigned long)val;
|
||||
}
|
||||
*lvalp = jiffies_to_clock_t(lval);
|
||||
@@ -2519,7 +2597,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
|
||||
int *valp,
|
||||
int write, void *data)
|
||||
{
|
||||
@@ -2529,10 +2607,10 @@ static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp,
|
||||
int val = *valp;
|
||||
unsigned long lval;
|
||||
if (val < 0) {
|
||||
*negp = -1;
|
||||
*negp = true;
|
||||
lval = (unsigned long)-val;
|
||||
} else {
|
||||
*negp = 0;
|
||||
*negp = false;
|
||||
lval = (unsigned long)val;
|
||||
}
|
||||
*lvalp = jiffies_to_msecs(lval);
|
||||
@@ -2629,6 +2707,157 @@ static int proc_do_cad_pid(struct ctl_table *table, int write,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* proc_do_large_bitmap - read/write from/to a large bitmap
|
||||
* @table: the sysctl table
|
||||
* @write: %TRUE if this is a write to the sysctl file
|
||||
* @buffer: the user buffer
|
||||
* @lenp: the size of the user buffer
|
||||
* @ppos: file position
|
||||
*
|
||||
* The bitmap is stored at table->data and the bitmap length (in bits)
|
||||
* in table->maxlen.
|
||||
*
|
||||
* We use a range comma separated format (e.g. 1,3-4,10-10) so that
|
||||
* large bitmaps may be represented in a compact manner. Writing into
|
||||
* the file will clear the bitmap then update it with the given input.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int proc_do_large_bitmap(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int err = 0;
|
||||
bool first = 1;
|
||||
size_t left = *lenp;
|
||||
unsigned long bitmap_len = table->maxlen;
|
||||
unsigned long *bitmap = (unsigned long *) table->data;
|
||||
unsigned long *tmp_bitmap = NULL;
|
||||
char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
|
||||
|
||||
if (!bitmap_len || !left || (*ppos && !write)) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (write) {
|
||||
unsigned long page = 0;
|
||||
char *kbuf;
|
||||
|
||||
if (left > PAGE_SIZE - 1)
|
||||
left = PAGE_SIZE - 1;
|
||||
|
||||
page = __get_free_page(GFP_TEMPORARY);
|
||||
kbuf = (char *) page;
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kbuf, buffer, left)) {
|
||||
free_page(page);
|
||||
return -EFAULT;
|
||||
}
|
||||
kbuf[left] = 0;
|
||||
|
||||
tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
|
||||
GFP_KERNEL);
|
||||
if (!tmp_bitmap) {
|
||||
free_page(page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
proc_skip_char(&kbuf, &left, '\n');
|
||||
while (!err && left) {
|
||||
unsigned long val_a, val_b;
|
||||
bool neg;
|
||||
|
||||
err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
|
||||
sizeof(tr_a), &c);
|
||||
if (err)
|
||||
break;
|
||||
if (val_a >= bitmap_len || neg) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
val_b = val_a;
|
||||
if (left) {
|
||||
kbuf++;
|
||||
left--;
|
||||
}
|
||||
|
||||
if (c == '-') {
|
||||
err = proc_get_long(&kbuf, &left, &val_b,
|
||||
&neg, tr_b, sizeof(tr_b),
|
||||
&c);
|
||||
if (err)
|
||||
break;
|
||||
if (val_b >= bitmap_len || neg ||
|
||||
val_a > val_b) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (left) {
|
||||
kbuf++;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
|
||||
while (val_a <= val_b)
|
||||
set_bit(val_a++, tmp_bitmap);
|
||||
|
||||
first = 0;
|
||||
proc_skip_char(&kbuf, &left, '\n');
|
||||
}
|
||||
free_page(page);
|
||||
} else {
|
||||
unsigned long bit_a, bit_b = 0;
|
||||
|
||||
while (left) {
|
||||
bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
|
||||
if (bit_a >= bitmap_len)
|
||||
break;
|
||||
bit_b = find_next_zero_bit(bitmap, bitmap_len,
|
||||
bit_a + 1) - 1;
|
||||
|
||||
if (!first) {
|
||||
err = proc_put_char(&buffer, &left, ',');
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
err = proc_put_long(&buffer, &left, bit_a, false);
|
||||
if (err)
|
||||
break;
|
||||
if (bit_a != bit_b) {
|
||||
err = proc_put_char(&buffer, &left, '-');
|
||||
if (err)
|
||||
break;
|
||||
err = proc_put_long(&buffer, &left, bit_b, false);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
first = 0; bit_b++;
|
||||
}
|
||||
if (!err)
|
||||
err = proc_put_char(&buffer, &left, '\n');
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (write) {
|
||||
if (*ppos)
|
||||
bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
|
||||
else
|
||||
memcpy(bitmap, tmp_bitmap,
|
||||
BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
|
||||
}
|
||||
kfree(tmp_bitmap);
|
||||
*lenp -= left;
|
||||
*ppos += *lenp;
|
||||
return 0;
|
||||
} else {
|
||||
kfree(tmp_bitmap);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_PROC_FS */
|
||||
|
||||
int proc_dostring(struct ctl_table *table, int write,
|
||||
|
Reference in New Issue
Block a user