include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
@echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
- @if [ -z "$(SMP)" ] ; then echo -n " SMP" >> .ver; fi
+ @if [ -n "$(SMP)" ] ; then echo -n " SMP" >> .ver; fi
@if [ -f .name ]; then echo -n \-`cat .name` >> .ver; fi
@echo ' '`date`'"' >> .ver
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
asmlinkage int sys_idle(void)
{
+ if (current->pid != 0)
+ return -EPERM;
cpu_idle(NULL);
return 0;
}
number of unused buffer heads */
/*
- * How large a hash table do we need?
+ * Hash table mask..
*/
-#define HASH_PAGES_ORDER 4
-#define HASH_PAGES (1UL << HASH_PAGES_ORDER)
-#define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *))
-#define HASH_MASK (NR_HASH-1)
+static unsigned long bh_hash_mask = 0;
static int grow_buffers(int pri, int size);
}
}
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block))&HASH_MASK)
+#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
static inline void remove_from_hash_queue(struct buffer_head * bh)
needed = bdf_prm.b_un.nrefill * size;
while ((nr_free_pages > freepages.min*2) &&
- BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
+ (buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.max_percent * num_physpages) &&
grow_buffers(GFP_BUFFER, size)) {
obtained += PAGE_SIZE;
if (obtained >= needed)
*/
while (obtained < (needed >> 1) &&
nr_free_pages > freepages.min + 5 &&
- BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
grow_buffers(GFP_BUFFER, size))
obtained += PAGE_SIZE;
*/
void buffer_init(void)
{
- hash_table = (struct buffer_head **)
- __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER);
+ int order = 5; /* Currently maximum order.. */
+ unsigned int nr_hash;
+
+ nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
+ hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+
if (!hash_table)
panic("Failed to allocate buffer hash table\n");
- memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *));
+ memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
+ bh_hash_mask = nr_hash-1;
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head),
extern struct inode swapper_inode;
extern unsigned long page_cache_size;
extern int buffermem;
-#define BUFFER_MEM ((buffermem >> PAGE_SHIFT) + page_cache_size)
/* Incomplete types for prototype declarations: */
struct task_struct;
{VM_SWAPCTL, "swapctl",
&swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
{VM_SWAPOUT, "swapout_interval",
- &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
+ &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec},
{VM_FREEPG, "freepages",
&freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec},
{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
}
tmp = tmp->b_this_page;
} while (tmp != bh);
+
+ /* Refuse to swap out all buffer pages */
+ if ((buffermem >> PAGE_SHIFT) * 100 > (buffer_mem.min_percent * num_physpages))
+ goto next;
}
/* We can't throw away shared pages, but we do mark
*/
int free_memory_available(int nr)
{
+ int retval = 0;
unsigned long flags;
struct free_area_struct * list = NULL;
if (list->next->next == memory_head(list))
continue;
/* More than one item? We're ok */
+ retval = nr + 1;
break;
} while (--nr >= 0);
spin_unlock_irqrestore(&page_alloc_lock, flags);
- return nr + 1;
+ return retval;
}
static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
swapstat_t swapstats = {0};
buffer_mem_t buffer_mem = {
- 6, /* minimum percent buffer + cache memory */
- 20, /* borrow percent buffer + cache memory */
- 90 /* maximum percent buffer + cache memory */
+ 3, /* minimum percent buffer */
+ 10, /* borrow percent buffer */
+ 30 /* maximum percent buffer */
};
/*
* When are we next due for a page scan?
*/
-static int next_swap_jiffies = 0;
+static unsigned long next_swap_jiffies = 0;
/*
* How often do we do a pageout scan during normal conditions?
stop = 3;
if (gfp_mask & __GFP_WAIT)
stop = 0;
- if (BUFFER_MEM > buffer_mem.borrow_percent * num_physpages / 100)
+ if ((buffermem >> PAGE_SHIFT) * 100 > buffer_mem.borrow_percent * num_physpages)
state = 0;
switch (state) {
do {
case 0:
- if (BUFFER_MEM > (buffer_mem.min_percent * num_physpages /100) &&
- shrink_mmap(i, gfp_mask))
+ if (shrink_mmap(i, gfp_mask))
return 1;
state = 1;
case 1:
run_task_queue(&tq_disk);
schedule();
swapstats.wakeups++;
- /* Do the background pageout:
- * When we've got loads of memory, we try
- * (freepages.high - nr_free_pages) times to
- * free memory. As memory gets tighter, kswapd
- * gets more and more agressive. -- Rik.
+
+ /*
+ * Do the background pageout: be
+ * more aggressive if we're really
+ * low on free memory.
+ *
+ * Normally this is called 4 times
+ * a second if we need more memory,
+ * so this has a normal rate of
+ * X*4 pages of memory free'd per
+ * second. That rate goes up when
+ *
+ * - we're really low on memory (we get woken
+ * up a lot more)
+ * - other processes fail to allocate memory,
+ * at which time they try to do their own
+ * freeing.
+ *
+ * A "tries" value of 50 means up to 200 pages
+ * per second (1.6MB/s). This should be a /proc
+ * thing.
*/
- tries = freepages.high - nr_free_pages;
- if (tries < freepages.min) {
- tries = freepages.min;
- }
- if (nr_free_pages < freepages.low)
- tries <<= 1;
+ tries = 50;
+
while (tries--) {
int gfp_mask;
/*
* The swap_tick function gets called on every clock tick.
*/
-
void swap_tick(void)
{
unsigned long now, want;
case 0:
want = now;
/* Fall through */
- case 1 ... 2:
+ case 1 ... 3:
want_wakeup = 1;
default:
}
if ((long) (now - want) >= 0) {
- if (want_wakeup || (num_physpages * buffer_mem.max_percent / 100) < BUFFER_MEM) {
+ if (want_wakeup || (num_physpages * buffer_mem.max_percent) < (buffermem >> PAGE_SHIFT) * 100) {
/* Set the next wake-up time */
next_swap_jiffies = now + swapout_interval;
wake_up(&kswapd_wait);
unsigned long flags;
save_flags(flags);
cli();
- skb=skb_peek(&sk->receive_queue);
+ skb = skb_peek(&sk->receive_queue);
if(skb!=NULL)
atomic_inc(&skb->users);
restore_flags(flags);
- if(skb==NULL) /* shouldn't happen but .. */
- goto restart;
- return skb;
- }
- skb = skb_dequeue(&sk->receive_queue);
+ } else
+ skb = skb_dequeue(&sk->receive_queue);
+
if (!skb) /* Avoid race if someone beats us to the data */
goto restart;
return skb;
int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
- int err;
- err = copy_to_user(to, skb->h.raw+offset, size);
- if (err)
- {
- err = -EFAULT;
- }
+ int err = -EFAULT;
+
+ if (!copy_to_user(to, skb->h.raw + offset, size))
+ err = 0;
return err;
}
/*
* Copy a datagram to an iovec.
+ * Note: the iovec is modified during the copy.
*/
int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
int size)
{
- int err;
- err = memcpy_toiovec(to, skb->h.raw+offset, size);
- if (err)
- {
- err = -EFAULT;
- }
- return err;
+ return memcpy_toiovec(to, skb->h.raw + offset, size);
}
/*
/*
* Verify iovec
- * verify area does a simple check for completly bogus addresses
*
* Save time not doing verify_area. copy_*_user will make this work
* in any case.
}
/*
- * Copy kernel to iovec.
+ * Copy kernel to iovec. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
{
- int err;
+ int err = -EFAULT;
while(len>0)
{
if(iov->iov_len)
{
int copy = min(iov->iov_len, len);
- err = copy_to_user(iov->iov_base, kdata, copy);
- if (err)
+ if (copy_to_user(iov->iov_base, kdata, copy))
goto out;
kdata+=copy;
len-=copy;
}
/*
- * Copy iovec to kernel.
+ * Copy iovec to kernel. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/
{
int err = -EFAULT;
- while(offset>0)
+ /* Skip over the finished iovecs */
+ while(offset >= iov->iov_len)
{
- if (offset > iov->iov_len)
- {
- offset -= iov->iov_len;
- }
- else
- {
- u8 *base = iov->iov_base + offset;
- int copy = min(len, iov->iov_len - offset);
-
- offset = 0;
-
- if (copy_from_user(kdata, base, copy))
- goto out;
- len-=copy;
- kdata+=copy;
- }
+ offset -= iov->iov_len;
iov++;
}
- while (len>0)
+ while (len > 0)
{
- int copy = min(len, iov->iov_len);
+ u8 *base = iov->iov_base + offset;
+ int copy = min(len, iov->iov_len - offset);
- if (copy_from_user(kdata, iov->iov_base, copy))
+ offset = 0;
+ if (copy_from_user(kdata, base, copy))
goto out;
- len-=copy;
- kdata+=copy;
+ len -= copy;
+ kdata += copy;
iov++;
}
err = 0;
int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
int offset, unsigned int len, int *csump)
{
- int partial_cnt = 0;
- int err = 0;
- int csum;
+ int csum = *csump;
+ int partial_cnt = 0, err = 0;
- do {
- int copy = iov->iov_len - offset;
-
- if (copy > 0) {
- u8 *base = iov->iov_base + offset;
-
- /* Normal case (single iov component) is fastly detected */
- if (len <= copy) {
- *csump = csum_and_copy_from_user(base, kdata,
- len, *csump, &err);
- goto out;
- }
-
- partial_cnt = copy % 4;
- if (partial_cnt) {
- copy -= partial_cnt;
- if (copy_from_user(kdata + copy, base + copy,
- partial_cnt))
- goto out_fault;
- }
-
- *csump = csum_and_copy_from_user(base, kdata, copy,
- *csump, &err);
- if (err)
- goto out;
- len -= copy + partial_cnt;
- kdata += copy + partial_cnt;
- iov++;
- break;
- }
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len)
+ {
+ offset -= iov->iov_len;
iov++;
- offset = -copy;
- } while (offset > 0);
-
- csum = *csump;
+ }
while (len > 0)
{
- u8 *base = iov->iov_base;
- unsigned int copy = min(len, iov->iov_len);
+ u8 *base = iov->iov_base + offset;
+ unsigned int copy = min(len, iov->iov_len - offset);
+ offset = 0;
/* There is a remnant from previous iov. */
if (partial_cnt)
{
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
+ struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
struct sk_buff *skb;
struct device *dev;
- struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
unsigned short proto=0;
int err;
return -EMSGSIZE;
dev_lock_list();
+ err = -ENOBUFS;
skb = sock_wmalloc(sk, len+dev->hard_header_len+15, 0, GFP_KERNEL);
/*
*/
if (skb == NULL)
- {
- dev_unlock_list();
- return(-ENOBUFS);
- }
+ goto out_unlock;
/*
* Fill it in
skb->data -= dev->hard_header_len;
skb->tail -= dev->hard_header_len;
}
+
+ /* Returns -EFAULT on error */
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->priority;
- dev_unlock_list();
+ if (err)
+ goto out_free;
+
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_free;
/*
* Now send it
*/
- if (err)
- {
- err = -EFAULT;
- }
- else
- {
- if (!(dev->flags & IFF_UP))
- {
- err = -ENETDOWN;
- }
- }
-
- if (err)
- {
- kfree_skb(skb);
- return err;
- }
-
+ dev_unlock_list();
dev_queue_xmit(skb);
return(len);
+
+out_free:
+ kfree_skb(skb);
+out_unlock:
+ dev_unlock_list();
+ return err;
}
#endif
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
+ struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
struct sk_buff *skb;
struct device *dev;
- struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
unsigned short proto;
- int ifindex;
- int err;
- int reserve = 0;
+ unsigned char *addr;
+ int ifindex, err, reserve = 0;
/*
* Check the flags.
*/
if (saddr == NULL) {
- ifindex = sk->protinfo.af_packet->ifindex;
- proto = sk->num;
+ ifindex = sk->protinfo.af_packet->ifindex;
+ proto = sk->num;
+ addr = NULL;
} else {
if (msg->msg_namelen < sizeof(struct sockaddr_ll))
return -EINVAL;
- ifindex = saddr->sll_ifindex;
- proto = saddr->sll_protocol;
+ ifindex = saddr->sll_ifindex;
+ proto = saddr->sll_protocol;
+ addr = saddr->sll_addr;
}
dev = dev_get_by_index(ifindex);
dev_lock_list();
- skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
- if (skb==NULL) {
- dev_unlock_list();
- return err;
- }
+ skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (skb==NULL)
+ goto out_unlock;
skb_reserve(skb, (dev->hard_header_len+15)&~15);
skb->nh.raw = skb->data;
if (dev->hard_header) {
- if (dev->hard_header(skb, dev, ntohs(proto),
- saddr ? saddr->sll_addr : NULL,
- NULL, len) < 0
- && sock->type == SOCK_DGRAM) {
- kfree_skb(skb);
- dev_unlock_list();
- return -EINVAL;
- }
+ int res;
+ err = -EINVAL;
+ res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
if (sock->type != SOCK_DGRAM) {
skb->tail = skb->data;
skb->len = 0;
- }
+ } else if (res < 0)
+ goto out_free;
}
+ /* Returns -EFAULT on error */
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->priority;
- dev_unlock_list();
+ if (err)
+ goto out_free;
+
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_free;
/*
* Now send it
*/
- if (err) {
- err = -EFAULT;
- } else {
- if (!(dev->flags & IFF_UP))
- err = -ENETDOWN;
- }
-
- if (err) {
- kfree_skb(skb);
- return err;
- }
-
+ dev_unlock_list();
dev_queue_xmit(skb);
return(len);
+
+out_free:
+ kfree_skb(skb);
+out_unlock:
+ dev_unlock_list();
+ return err;
}
static void packet_destroy_timer(unsigned long data)
static int packet_create(struct socket *sock, int protocol)
{
struct sock *sk;
+ int err;
if (!suser())
return -EPERM;
sock->state = SS_UNCONNECTED;
MOD_INC_USE_COUNT;
+
+ err = -ENOBUFS;
sk = sk_alloc(AF_PACKET, GFP_KERNEL, 1);
- if (sk == NULL) {
- MOD_DEC_USE_COUNT;
- return -ENOBUFS;
- }
+ if (sk == NULL)
+ goto out;
sk->reuse = 1;
+ sock->ops = &packet_ops;
#ifdef CONFIG_SOCK_PACKET
if (sock->type == SOCK_PACKET)
sock->ops = &packet_ops_spkt;
- else
#endif
- sock->ops = &packet_ops;
sock_init_data(sock,sk);
sk->protinfo.af_packet = kmalloc(sizeof(struct packet_opt), GFP_KERNEL);
- if (sk->protinfo.af_packet == NULL) {
- sk_free(sk);
- MOD_DEC_USE_COUNT;
- return -ENOBUFS;
- }
+ if (sk->protinfo.af_packet == NULL)
+ goto out_free;
memset(sk->protinfo.af_packet, 0, sizeof(struct packet_opt));
sk->zapped=0;
sk->family = AF_PACKET;
* Attach a protocol block
*/
+ sk->protinfo.af_packet->prot_hook.func = packet_rcv;
#ifdef CONFIG_SOCK_PACKET
if (sock->type == SOCK_PACKET)
sk->protinfo.af_packet->prot_hook.func = packet_rcv_spkt;
- else
#endif
- sk->protinfo.af_packet->prot_hook.func = packet_rcv;
-
sk->protinfo.af_packet->prot_hook.data = (void *)sk;
if (protocol) {
sklist_insert_socket(&packet_sklist, sk);
return(0);
+
+out_free:
+ sk_free(sk);
+out:
+ MOD_DEC_USE_COUNT;
+ return err;
}
/*
/* We can't use skb_copy_datagram here */
err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
- if (err) {
- err = -EFAULT;
+ if (err)
goto out_free;
- }
sk->stamp=skb->stamp;
if (msg->msg_name)
static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
{
- int err;
struct packet_mclist *ml, *i;
struct device *dev;
+ int err;
rtnl_shlock();
- dev = dev_get_by_index(mreq->mr_ifindex);
-
- i = NULL;
err = -ENODEV;
+ dev = dev_get_by_index(mreq->mr_ifindex);
if (!dev)
goto done;
+
err = -EINVAL;
if (mreq->mr_alen > dev->addr_len)
goto done;
+ err = -ENOBUFS;
i = (struct packet_mclist *)kmalloc(sizeof(*i), GFP_KERNEL);
+ if (i == NULL)
+ goto done;
+ err = 0;
for (ml=sk->protinfo.af_packet->mclist; ml; ml=ml->next) {
if (ml->ifindex == mreq->mr_ifindex &&
ml->type == mreq->mr_type &&
ml->alen == mreq->mr_alen &&
memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) {
ml->count++;
- err = 0;
+ /* Free the new element ... */
+ kfree(i);
goto done;
}
}
- err = -ENOBUFS;
- if (i == NULL)
- goto done;
+
i->type = mreq->mr_type;
i->ifindex = mreq->mr_ifindex;
i->alen = mreq->mr_alen;
i->next = sk->protinfo.af_packet->mclist;
sk->protinfo.af_packet->mclist = i;
packet_dev_mc(dev, i, +1);
- i = NULL;
- err = 0;
done:
rtnl_shunlock();
- if (i)
- kfree(i);
return err;
}
case FIOGETOWN:
case SIOCGPGRP:
return put_user(sk->proc, (int *)arg);
- return(0);
case SIOCGSTAMP:
if(sk->stamp.tv_sec==0)
return -ENOENT;
- err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
- if (err)
- err = -EFAULT;
+ err = -EFAULT;
+ if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+ err = 0;
return err;
case SIOCGIFFLAGS:
#ifndef CONFIG_INET
char address[MAX_SOCK_ADDR];
struct iovec iov[UIO_FASTIOV];
unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */
- struct msghdr msg_sys;
- int err= -EINVAL;
- int total_len;
unsigned char *ctl_buf = ctl;
+ struct msghdr msg_sys;
+ int err, total_len;
lock_kernel();
- err=-EFAULT;
+ err = -EFAULT;
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
goto out;
+
/* do not move before msg_sys is valid */
- if (msg_sys.msg_iovlen>UIO_MAXIOV)
+ err = -EINVAL;
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
goto out;
+
/* This will also move the address data into kernel space */
err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
if (err < 0)
sock = sockfd_lookup(fd, &err);
if (!sock)
- goto out;
+ goto out_freeiov;
if (msg_sys.msg_controllen)
{
if (ctl_buf != ctl)
sock_kfree_s(sock->sk, ctl_buf, msg_sys.msg_controllen);
failed2:
+ sockfd_put(sock);
+out_freeiov:
if (msg_sys.msg_iov != iov)
kfree(msg_sys.msg_iov);
- sockfd_put(sock);
out:
unlock_kernel();
return err;
int *uaddr_len;
lock_kernel();
+ err=-EFAULT;
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
- {
- err=-EFAULT;
goto out;
- }
- if (msg_sys.msg_iovlen>UIO_MAXIOV)
- {
- err=-EINVAL;
+
+ err=-EINVAL;
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
goto out;
- }
/*
* Save the user-mode address (verify_iovec will change the
skb=sock_alloc_send_skb(sk, len, 0, nonblock, &err); /* Marker object */
if(skb==NULL)
- return err;
+ goto out;
memcpy(&UNIXCB(skb), cmsg, sizeof(*cmsg));
- if (len)
- memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ if (len) {
+ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov,
+ len);
+ if (err)
+ goto out_free;
+ }
+
sk->state=TCP_CLOSE;
other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
if(other==NULL)
- {
- kfree_skb(skb);
- return err;
- }
+ goto out_free;
other->ack_backlog++;
unix_peer(sk)=other;
skb_queue_tail(&other->receive_queue,skb);
if (!sk->protinfo.af_unix.addr)
unix_autobind(sock);
return 0;
+
+out_free:
+ kfree_skb(skb);
+out:
+ return err;
}
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
- unix_socket *other;
struct sockaddr_un *sunaddr=msg->msg_name;
+ unix_socket *other;
int namelen = 0; /* fake GCC */
int err;
unsigned hash;
unix_autobind(sock);
skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
if (skb==NULL)
- return err;
+ goto out;
memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred));
UNIXCB(skb).attr = msg->msg_flags;
unix_attach_fds(scm, skb);
skb->h.raw = skb->data;
- memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ if (err)
+ goto out_free;
other = unix_peer(sk);
if (other && other->dead)
unix_unlock(other);
unix_peer(sk)=NULL;
other = NULL;
- if (sunaddr == NULL) {
- kfree_skb(skb);
- return -ECONNRESET;
- }
+ err = -ECONNRESET;
+ if (sunaddr == NULL)
+ goto out_free;
}
if (!other)
{
other = unix_find_other(sunaddr, namelen, sk->type, hash, &err);
-
if (other==NULL)
- {
- kfree_skb(skb);
- return err;
- }
+ goto out_free;
+ err = -EINVAL;
if (!unix_may_send(sk, other))
- {
- unix_unlock(other);
- kfree_skb(skb);
- return -EINVAL;
- }
+ goto out_unlock;
}
skb_queue_tail(&other->receive_queue, skb);
if (!unix_peer(sk))
unix_unlock(other);
return len;
+
+out_unlock:
+ unix_unlock(other);
+out_free:
+ kfree_skb(skb);
+out:
+ return err;
}
}
chunk = min(skb->len, size);
- /* N.B. This could fail with a non-zero value (which means -EFAULT
- * and the non-zero value is the number of bytes not copied).
- */
+ /* N.B. This could fail with -EFAULT */
memcpy_toiovec(msg->msg_iov, skb->data, chunk);
copied += chunk;
size -= chunk;