loop: refactor: extract subfunction get_next_free_loop()
Extract subfunction get_next_free_loop() from set_loop()
Also fix miss free(try) when stat(try) and mknod fail
function                                             old     new   delta
set_loop                                             807     790     -17
Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists")
Signed-off-by: Xiaoming Ni <nixiaoming@huawei.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
			
			
This commit is contained in:
		
				
					committed by
					
						 Denys Vlasenko
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							90456a6aa3
						
					
				
				
					commit
					ddccf6cd2f
				
			
							
								
								
									
										56
									
								
								libbb/loop.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								libbb/loop.c
									
									
									
									
									
								
							| @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) | |||||||
| 	return loopdevno; /* can be -1 if error */ | 	return loopdevno; /* can be -1 if error */ | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int get_next_free_loop(char *dev, int id) | ||||||
|  | { | ||||||
|  | 	int loopdevno; | ||||||
|  |  | ||||||
|  | 	loopdevno = get_free_loop(); | ||||||
|  | 	if (loopdevno != -1) { | ||||||
|  | 		/* loopdevno is -2 (use id) or >= 0 (use id = loopdevno): */ | ||||||
|  | 		if (loopdevno >= 0) | ||||||
|  | 			id = loopdevno; | ||||||
|  | 		sprintf(dev, LOOP_FORMAT, id); | ||||||
|  | 	} | ||||||
|  | 	return loopdevno; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Returns opened fd to the loop device, <0 on error. | /* Returns opened fd to the loop device, <0 on error. | ||||||
|  * *device is loop device to use, or if *device==NULL finds a loop device to |  * *device is loop device to use, or if *device==NULL finds a loop device to | ||||||
|  * mount it on and sets *device to a strdup of that loop device name. |  * mount it on and sets *device to a strdup of that loop device name. | ||||||
| @@ -123,30 +137,27 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||||||
|  |  | ||||||
| 	try = *device; | 	try = *device; | ||||||
| 	if (!try) { | 	if (!try) { | ||||||
|  get_free_loopN: |  | ||||||
| 		i = get_free_loop(); |  | ||||||
| 		if (i == -1) { |  | ||||||
| 			close(ffd); |  | ||||||
| 			return -1; /* no free loop devices */ |  | ||||||
| 		} |  | ||||||
| 		if (i >= 0) { |  | ||||||
| 			try = xasprintf(LOOP_FORMAT, i); |  | ||||||
| 			goto open_lfd; |  | ||||||
| 		} |  | ||||||
| 		/* i == -2: no /dev/loop-control. Do an old-style search for a free device */ |  | ||||||
| 		try = dev; | 		try = dev; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Find a loop device */ | 	/* Find a loop device */ | ||||||
| 	/* 0xfffff is a max possible minor number in Linux circa 2010 */ | 	/* 0xfffff is a max possible minor number in Linux circa 2010 */ | ||||||
| 	for (i = 0; i <= 0xfffff; i++) { | 	for (i = 0; i <= 0xfffff; i++) { | ||||||
| 		sprintf(dev, LOOP_FORMAT, i); | 		if (!*device) { | ||||||
|  | 			rc = get_next_free_loop(dev, i); | ||||||
|  | 			if (rc == -1) | ||||||
|  | 				break; /* no free loop devices (or other error in LOOP_CTL_GET_FREE) */ | ||||||
|  | 			if (rc >= 0) | ||||||
|  | 				/* /dev/loop-control gave us the next free /dev/loopN */ | ||||||
|  | 				goto open_lfd; | ||||||
|  | 			/* else: sequential /dev/loopN, needs to be tested/maybe_created */ | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) | 		IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) | ||||||
| 		if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { | 		if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { | ||||||
| 			if (ENABLE_FEATURE_MOUNT_LOOP_CREATE | 			if (ENABLE_FEATURE_MOUNT_LOOP_CREATE | ||||||
| 			 && errno == ENOENT | 			 && errno == ENOENT | ||||||
| 			 && try == dev | 			 && (!*device) | ||||||
| 			) { | 			) { | ||||||
| 				/* Node doesn't exist, try to create it */ | 				/* Node doesn't exist, try to create it */ | ||||||
| 				if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) | 				if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) | ||||||
| @@ -179,13 +190,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||||||
| 			/* Associate free loop device with file */ | 			/* Associate free loop device with file */ | ||||||
| 			if (ioctl(lfd, LOOP_SET_FD, ffd)) { | 			if (ioctl(lfd, LOOP_SET_FD, ffd)) { | ||||||
| 				/* Ouch. Are we racing with other mount? */ | 				/* Ouch. Are we racing with other mount? */ | ||||||
| 				if (!*device   /* yes */ | 				if (!*device) { | ||||||
| 				 && try != dev /* tried a _kernel-offered_ loopN? */ |  | ||||||
| 				) { |  | ||||||
| 					free(try); |  | ||||||
| 					close(lfd); | 					close(lfd); | ||||||
| //TODO: add "if (--failcount != 0) ..."? | //TODO: add "if (--failcount != 0) ..."? | ||||||
| 					goto get_free_loopN; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				goto close_and_try_next_loopN; | 				goto close_and_try_next_loopN; | ||||||
| 			} | 			} | ||||||
| @@ -209,8 +217,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||||||
| 			} | 			} | ||||||
| 			if (rc == 0) { | 			if (rc == 0) { | ||||||
| 				/* SUCCESS! */ | 				/* SUCCESS! */ | ||||||
| 				if (try != dev) /* tried a kernel-offered free loopN? */ |  | ||||||
| 					*device = try; /* malloced */ |  | ||||||
| 				if (!*device)   /* was looping in search of free "/dev/loopN"? */ | 				if (!*device)   /* was looping in search of free "/dev/loopN"? */ | ||||||
| 					*device = xstrdup(dev); | 					*device = xstrdup(dev); | ||||||
| 				rc = lfd; /* return this */ | 				rc = lfd; /* return this */ | ||||||
| @@ -218,16 +224,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||||||
| 			} | 			} | ||||||
| 			/* failure, undo LOOP_SET_FD */ | 			/* failure, undo LOOP_SET_FD */ | ||||||
| 			ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary | 			ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary | ||||||
| 		} else { |  | ||||||
| 			/* device is not free (rc == 0), or error other than ENXIO */ |  | ||||||
| 			if (rc == 0	/* device is not free? */ |  | ||||||
| 			 && !*device	/* racing with other mount? */ |  | ||||||
| 			 && try != dev	/* tried a _kernel-offered_ loopN? */ |  | ||||||
| 			) { |  | ||||||
| 				free(try); |  | ||||||
| 				close(lfd); |  | ||||||
| 				goto get_free_loopN; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  close_and_try_next_loopN: |  close_and_try_next_loopN: | ||||||
| 		close(lfd); | 		close(lfd); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user