diff options
Diffstat (limited to 'drivers/block/aoe/aoecmd.c')
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 117 |
1 files changed, 83 insertions, 34 deletions
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 1be5150bcd3b..b49e06ef121e 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -106,45 +106,104 @@ ifrotate(struct aoetgt *t) | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | static void | ||
110 | skb_pool_put(struct aoedev *d, struct sk_buff *skb) | ||
111 | { | ||
112 | if (!d->skbpool_hd) | ||
113 | d->skbpool_hd = skb; | ||
114 | else | ||
115 | d->skbpool_tl->next = skb; | ||
116 | d->skbpool_tl = skb; | ||
117 | } | ||
118 | |||
119 | static struct sk_buff * | ||
120 | skb_pool_get(struct aoedev *d) | ||
121 | { | ||
122 | struct sk_buff *skb; | ||
123 | |||
124 | skb = d->skbpool_hd; | ||
125 | if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { | ||
126 | d->skbpool_hd = skb->next; | ||
127 | skb->next = NULL; | ||
128 | return skb; | ||
129 | } | ||
130 | if (d->nskbpool < NSKBPOOLMAX | ||
131 | && (skb = new_skb(ETH_ZLEN))) { | ||
132 | d->nskbpool++; | ||
133 | return skb; | ||
134 | } | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | /* freeframe is where we do our load balancing so it's a little hairy. */ | ||
109 | static struct frame * | 139 | static struct frame * |
110 | freeframe(struct aoedev *d) | 140 | freeframe(struct aoedev *d) |
111 | { | 141 | { |
112 | struct frame *f, *e; | 142 | struct frame *f, *e, *rf; |
113 | struct aoetgt **t; | 143 | struct aoetgt **t; |
114 | ulong n; | 144 | struct sk_buff *skb; |
115 | 145 | ||
116 | if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ | 146 | if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ |
117 | printk(KERN_ERR "aoe: NULL TARGETS!\n"); | 147 | printk(KERN_ERR "aoe: NULL TARGETS!\n"); |
118 | return NULL; | 148 | return NULL; |
119 | } | 149 | } |
120 | t = d->targets; | 150 | t = d->tgt; |
121 | do { | 151 | t++; |
122 | if (t != d->htgt | 152 | if (t >= &d->targets[NTARGETS] || !*t) |
123 | && (*t)->ifp->nd | 153 | t = d->targets; |
124 | && (*t)->nout < (*t)->maxout) { | 154 | for (;;) { |
125 | n = (*t)->nframes; | 155 | if ((*t)->nout < (*t)->maxout |
156 | && t != d->htgt | ||
157 | && (*t)->ifp->nd) { | ||
158 | rf = NULL; | ||
126 | f = (*t)->frames; | 159 | f = (*t)->frames; |
127 | e = f + n; | 160 | e = f + (*t)->nframes; |
128 | for (; f < e; f++) { | 161 | for (; f < e; f++) { |
129 | if (f->tag != FREETAG) | 162 | if (f->tag != FREETAG) |
130 | continue; | 163 | continue; |
131 | if (atomic_read(&skb_shinfo(f->skb)->dataref) | 164 | skb = f->skb; |
165 | if (!skb | ||
166 | && !(f->skb = skb = new_skb(ETH_ZLEN))) | ||
167 | continue; | ||
168 | if (atomic_read(&skb_shinfo(skb)->dataref) | ||
132 | != 1) { | 169 | != 1) { |
133 | n--; | 170 | if (!rf) |
171 | rf = f; | ||
134 | continue; | 172 | continue; |
135 | } | 173 | } |
136 | skb_shinfo(f->skb)->nr_frags = 0; | 174 | gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; |
137 | f->skb->data_len = 0; | 175 | skb_trim(skb, 0); |
138 | skb_trim(f->skb, 0); | ||
139 | d->tgt = t; | 176 | d->tgt = t; |
140 | ifrotate(*t); | 177 | ifrotate(*t); |
141 | return f; | 178 | return f; |
142 | } | 179 | } |
143 | if (n == 0) /* slow polling network card */ | 180 | /* Work can be done, but the network layer is |
181 | holding our precious packets. Try to grab | ||
182 | one from the pool. */ | ||
183 | f = rf; | ||
184 | if (f == NULL) { /* more paranoia */ | ||
185 | printk(KERN_ERR | ||
186 | "aoe: freeframe: %s.\n", | ||
187 | "unexpected null rf"); | ||
188 | d->flags |= DEVFL_KICKME; | ||
189 | return NULL; | ||
190 | } | ||
191 | skb = skb_pool_get(d); | ||
192 | if (skb) { | ||
193 | skb_pool_put(d, f->skb); | ||
194 | f->skb = skb; | ||
195 | goto gotone; | ||
196 | } | ||
197 | (*t)->dataref++; | ||
198 | if ((*t)->nout == 0) | ||
144 | d->flags |= DEVFL_KICKME; | 199 | d->flags |= DEVFL_KICKME; |
145 | } | 200 | } |
201 | if (t == d->tgt) /* we've looped and found nada */ | ||
202 | break; | ||
146 | t++; | 203 | t++; |
147 | } while (t < &d->targets[NTARGETS] && *t); | 204 | if (t >= &d->targets[NTARGETS] || !*t) |
205 | t = d->targets; | ||
206 | } | ||
148 | return NULL; | 207 | return NULL; |
149 | } | 208 | } |
150 | 209 | ||
@@ -894,33 +953,23 @@ addtgt(struct aoedev *d, char *addr, ulong nframes) | |||
894 | return NULL; | 953 | return NULL; |
895 | 954 | ||
896 | t = kcalloc(1, sizeof *t, GFP_ATOMIC); | 955 | t = kcalloc(1, sizeof *t, GFP_ATOMIC); |
956 | if (!t) | ||
957 | return NULL; | ||
897 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); | 958 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); |
898 | if (!t || !f) | 959 | if (!f) { |
899 | goto bail; | 960 | kfree(t); |
961 | return NULL; | ||
962 | } | ||
963 | |||
900 | t->nframes = nframes; | 964 | t->nframes = nframes; |
901 | t->frames = f; | 965 | t->frames = f; |
902 | e = f + nframes; | 966 | e = f + nframes; |
903 | for (; f < e; f++) { | 967 | for (; f < e; f++) |
904 | f->tag = FREETAG; | 968 | f->tag = FREETAG; |
905 | f->skb = new_skb(ETH_ZLEN); | ||
906 | if (!f->skb) | ||
907 | break; | ||
908 | } | ||
909 | if (f != e) { | ||
910 | while (f > t->frames) { | ||
911 | f--; | ||
912 | dev_kfree_skb(f->skb); | ||
913 | } | ||
914 | goto bail; | ||
915 | } | ||
916 | memcpy(t->addr, addr, sizeof t->addr); | 969 | memcpy(t->addr, addr, sizeof t->addr); |
917 | t->ifp = t->ifs; | 970 | t->ifp = t->ifs; |
918 | t->maxout = t->nframes; | 971 | t->maxout = t->nframes; |
919 | return *tt = t; | 972 | return *tt = t; |
920 | bail: | ||
921 | kfree(t); | ||
922 | kfree(f); | ||
923 | return NULL; | ||
924 | } | 973 | } |
925 | 974 | ||
926 | void | 975 | void |