cache: tolerate short writes in print_slot
sendfile() can return after a short read/write, so we may need to call it more than once. As suggested in the manual page, we fall back to read/write if sendfile fails with EINVAL or ENOSYS. On the read/write path, use write_in_full which deals with short writes. Signed-off-by: Hristo Venev <hristo@venev.name> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									4c520cefc9
								
							
						
					
					
						commit
						852cb3b0e2
					
				
							
								
								
									
										45
									
								
								cache.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								cache.c
									
									
									
									
									
								
							| @ -85,40 +85,45 @@ static int close_slot(struct cache_slot *slot) | |||||||
| /* Print the content of the active cache slot (but skip the key). */ | /* Print the content of the active cache slot (but skip the key). */ | ||||||
| static int print_slot(struct cache_slot *slot) | static int print_slot(struct cache_slot *slot) | ||||||
| { | { | ||||||
|  | 	off_t off; | ||||||
| #ifdef HAVE_LINUX_SENDFILE | #ifdef HAVE_LINUX_SENDFILE | ||||||
| 	off_t start_off; | 	off_t size; | ||||||
| 	int ret; | #endif | ||||||
| 
 | 
 | ||||||
| 	start_off = slot->keylen + 1; | 	off = slot->keylen + 1; | ||||||
|  | 
 | ||||||
|  | #ifdef HAVE_LINUX_SENDFILE | ||||||
|  | 	size = slot->cache_st.st_size; | ||||||
| 
 | 
 | ||||||
| 	do { | 	do { | ||||||
| 		ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off, | 		ssize_t ret; | ||||||
| 				slot->cache_st.st_size - start_off); | 		ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			if (errno == EAGAIN || errno == EINTR) | 			if (errno == EAGAIN || errno == EINTR) | ||||||
| 				continue; | 				continue; | ||||||
|  | 			/* Fall back to read/write on EINVAL or ENOSYS */ | ||||||
|  | 			if (errno == EINVAL || errno == ENOSYS) | ||||||
|  | 				break; | ||||||
| 			return errno; | 			return errno; | ||||||
| 		} | 		} | ||||||
| 		return 0; | 		if (off == size) | ||||||
|  | 			return 0; | ||||||
| 	} while (1); | 	} while (1); | ||||||
| #else | #endif | ||||||
| 	ssize_t i, j; |  | ||||||
| 
 | 
 | ||||||
| 	i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET); | 	if (lseek(slot->cache_fd, off, SEEK_SET) != off) | ||||||
| 	if (i != slot->keylen + 1) |  | ||||||
| 		return errno; | 		return errno; | ||||||
| 
 | 
 | ||||||
| 	do { | 	do { | ||||||
| 		i = j = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); | 		ssize_t ret; | ||||||
| 		if (i > 0) | 		ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); | ||||||
| 			j = xwrite(STDOUT_FILENO, slot->buf, i); | 		if (ret < 0) | ||||||
| 	} while (i > 0 && j == i); | 			return errno; | ||||||
| 
 | 		if (ret == 0) | ||||||
| 	if (i < 0 || j != i) | 			return 0; | ||||||
| 		return errno; | 		if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0) | ||||||
| 	else | 			return errno; | ||||||
| 		return 0; | 	} while (1); | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Check if the slot has expired */ | /* Check if the slot has expired */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user