Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ppp_generic - fix regressions caused by IDR conversion

The commits:

7a95d267fb62cd6b80ef73be0592bbbe1dbd5df7
("net: ppp_generic - use idr technique instead of cardmaps")

ab5024ab23b78c86a0a1425defcdde48710fe449
("net: ppp_generic - use DEFINE_IDR for static initialization")

introduced usage of IDR functionality but broke userspace side.

Before this commits it was possible to allocate new ppp interface with
specified number. Now it fails with EINVAL. Fix it by trying to
allocate interface with specified unit number and return EEXIST if
fail which allow pppd to ask us to allocate new unit number.

And fix messages on memory allocation fails - add details that it's
PPP module who is complaining.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Cyrill Gorcunov and committed by
David S. Miller
85997576 a6d0b91a

+37 -6
+37 -6
drivers/net/ppp_generic.c
··· 250 250 static int ppp_disconnect_channel(struct channel *pch); 251 251 static void ppp_destroy_channel(struct channel *pch); 252 252 static int unit_get(struct idr *p, void *ptr); 253 + static int unit_set(struct idr *p, void *ptr, int n); 253 254 static void unit_put(struct idr *p, int n); 254 255 static void *unit_find(struct idr *p, int n); 255 256 ··· 2433 2432 } else { 2434 2433 if (unit_find(&ppp_units_idr, unit)) 2435 2434 goto out2; /* unit already exists */ 2436 - else { 2437 - /* darn, someone is cheating us? */ 2438 - *retp = -EINVAL; 2435 + /* 2436 + * if caller need a specified unit number 2437 + * lets try to satisfy him, otherwise -- 2438 + * he should better ask us for new unit number 2439 + * 2440 + * NOTE: yes I know that returning EEXIST it's not 2441 + * fair but at least pppd will ask us to allocate 2442 + * new unit in this case so user is happy :) 2443 + */ 2444 + unit = unit_set(&ppp_units_idr, ppp, unit); 2445 + if (unit < 0) 2439 2446 goto out2; 2440 - } 2441 2447 } 2442 2448 2443 2449 /* Initialize the new ppp unit */ ··· 2685 2677 * by holding all_ppp_mutex 2686 2678 */ 2687 2679 2680 + /* associate pointer with specified number */ 2681 + static int unit_set(struct idr *p, void *ptr, int n) 2682 + { 2683 + int unit, err; 2684 + 2685 + again: 2686 + if (!idr_pre_get(p, GFP_KERNEL)) { 2687 + printk(KERN_ERR "PPP: No free memory for idr\n"); 2688 + return -ENOMEM; 2689 + } 2690 + 2691 + err = idr_get_new_above(p, ptr, n, &unit); 2692 + if (err == -EAGAIN) 2693 + goto again; 2694 + 2695 + if (unit != n) { 2696 + idr_remove(p, unit); 2697 + return -EINVAL; 2698 + } 2699 + 2700 + return unit; 2701 + } 2702 + 2688 2703 /* get new free unit number and associate pointer with it */ 2689 2704 static int unit_get(struct idr *p, void *ptr) 2690 2705 { 2691 2706 int unit, err; 2692 2707 2693 2708 again: 2694 - if (idr_pre_get(p, GFP_KERNEL) == 0) { 2695 - printk(KERN_ERR "Out of memory expanding drawable idr\n"); 2709 + if (!idr_pre_get(p, GFP_KERNEL)) { 2710 + printk(KERN_ERR "PPP: No free memory for idr\n"); 2696 2711 return -ENOMEM; 2697 2712 } 2698 2713