btrfs-progs: Error handling in scrub_progress_cycle() thread

consolidate error handling to ensure that peer_fd
is closed on error paths.  Add a couple comments
to the error handling after the thread is complete.

Note that scrub_progress_cycle returns negative
errnos on any error.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
master
Eric Sandeen 2013-03-04 16:45:37 -06:00 committed by David Sterba
parent 6626354fdf
commit b79d4a217f
1 changed files with 38 additions and 21 deletions

View File

@ -840,9 +840,11 @@ static void *progress_one_dev(void *ctx)
return NULL; return NULL;
} }
/* nb: returns a negative errno via ERR_PTR */
static void *scrub_progress_cycle(void *ctx) static void *scrub_progress_cycle(void *ctx)
{ {
int ret; int ret;
int perr = 0; /* positive / pthread error returns */
int old; int old;
int i; int i;
char fsid[37]; char fsid[37];
@ -867,9 +869,9 @@ static void *scrub_progress_cycle(void *ctx)
struct sockaddr_un peer; struct sockaddr_un peer;
socklen_t peer_size = sizeof(peer); socklen_t peer_size = sizeof(peer);
ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); perr = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
if (ret) if (perr)
return ERR_PTR(-ret); goto out;
uuid_unparse(spc->fi->fsid, fsid); uuid_unparse(spc->fi->fsid, fsid);
@ -890,8 +892,10 @@ static void *scrub_progress_cycle(void *ctx)
while (1) { while (1) {
ret = poll(&accept_poll_fd, 1, 5 * 1000); ret = poll(&accept_poll_fd, 1, 5 * 1000);
if (ret == -1) if (ret == -1) {
return ERR_PTR(-errno); ret = -errno;
goto out;
}
if (ret) if (ret)
peer_fd = accept(spc->prg_fd, (struct sockaddr *)&peer, peer_fd = accept(spc->prg_fd, (struct sockaddr *)&peer,
&peer_size); &peer_size);
@ -909,42 +913,46 @@ static void *scrub_progress_cycle(void *ctx)
if (!sp->ret) if (!sp->ret)
continue; continue;
if (sp->ioctl_errno != ENOTCONN && if (sp->ioctl_errno != ENOTCONN &&
sp->ioctl_errno != ENODEV) sp->ioctl_errno != ENODEV) {
return ERR_PTR(-sp->ioctl_errno); ret = -sp->ioctl_errno;
goto out;
}
/* /*
* scrub finished or device removed, check the * scrub finished or device removed, check the
* finished flag. if unset, just use the last * finished flag. if unset, just use the last
* result we got for the current write and go * result we got for the current write and go
* on. flag should be set on next cycle, then. * on. flag should be set on next cycle, then.
*/ */
ret = pthread_mutex_lock(&sp_shared->progress_mutex); perr = pthread_mutex_lock(&sp_shared->progress_mutex);
if (ret) if (perr)
return ERR_PTR(-ret); goto out;
if (!sp_shared->stats.finished) { if (!sp_shared->stats.finished) {
ret = pthread_mutex_unlock( perr = pthread_mutex_unlock(
&sp_shared->progress_mutex); &sp_shared->progress_mutex);
if (ret) if (perr)
return ERR_PTR(-ret); goto out;
memcpy(sp, sp_last, sizeof(*sp)); memcpy(sp, sp_last, sizeof(*sp));
continue; continue;
} }
ret = pthread_mutex_unlock(&sp_shared->progress_mutex); perr = pthread_mutex_unlock(&sp_shared->progress_mutex);
if (ret) if (perr)
return ERR_PTR(-ret); goto out;
memcpy(sp, sp_shared, sizeof(*sp)); memcpy(sp, sp_shared, sizeof(*sp));
memcpy(sp_last, sp_shared, sizeof(*sp)); memcpy(sp_last, sp_shared, sizeof(*sp));
} }
if (peer_fd != -1) { if (peer_fd != -1) {
write_poll_fd.fd = peer_fd; write_poll_fd.fd = peer_fd;
ret = poll(&write_poll_fd, 1, 0); ret = poll(&write_poll_fd, 1, 0);
if (ret == -1) if (ret == -1) {
return ERR_PTR(-errno); ret = -errno;
goto out;
}
if (ret) { if (ret) {
ret = scrub_write_file( ret = scrub_write_file(
peer_fd, fsid, peer_fd, fsid,
&spc->progress[this * ndev], ndev); &spc->progress[this * ndev], ndev);
if (ret) if (ret)
return ERR_PTR(ret); goto out;
} }
close(peer_fd); close(peer_fd);
peer_fd = -1; peer_fd = -1;
@ -954,8 +962,14 @@ static void *scrub_progress_cycle(void *ctx)
ret = scrub_write_progress(spc->write_mutex, fsid, ret = scrub_write_progress(spc->write_mutex, fsid,
&spc->progress[this * ndev], ndev); &spc->progress[this * ndev], ndev);
if (ret) if (ret)
return ERR_PTR(ret); goto out;
} }
out:
if (peer_fd != -1)
close(peer_fd);
if (perr)
ret = -perr;
return ERR_PTR(ret);
} }
static struct scrub_file_record *last_dev_scrub( static struct scrub_file_record *last_dev_scrub(
@ -1373,11 +1387,14 @@ static int scrub_start(int argc, char **argv, int resume)
ret = pthread_cancel(t_prog); ret = pthread_cancel(t_prog);
if (!ret) if (!ret)
ret = pthread_join(t_prog, &terr); ret = pthread_join(t_prog, &terr);
/* check for errors from the handling of the progress thread */
if (do_print && ret) { if (do_print && ret) {
fprintf(stderr, "ERROR: progress thead handling failed: %s\n", fprintf(stderr, "ERROR: progress thread handling failed: %s\n",
strerror(ret)); strerror(ret));
} }
/* check for errors returned from the progress thread itself */
if (do_print && terr && terr != PTHREAD_CANCELED) { if (do_print && terr && terr != PTHREAD_CANCELED) {
fprintf(stderr, "ERROR: recording progress " fprintf(stderr, "ERROR: recording progress "
"failed: %s\n", strerror(-PTR_ERR(terr))); "failed: %s\n", strerror(-PTR_ERR(terr)));