source: branches/samba-3.5.x/client/mtab.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 6.2 KB
Line 
1/*
2 * mtab locking routines for use with mount.cifs and umount.cifs
3 * Copyright (C) 2008 Jeff Layton (jlayton@samba.org)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/*
20 * This code was copied from the util-linux-ng sources and modified:
21 *
22 * git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
23 *
24 * ...specifically from mount/fstab.c. That file has no explicit license. The
25 * "default" license for anything in that tree is apparently GPLv2+, so I
26 * believe we're OK to copy it here.
27 *
28 * Jeff Layton <jlayton@samba.org>
29 */
30
31#include <unistd.h>
32#include <errno.h>
33#include <stdio.h>
34#include <sys/time.h>
35#include <sys/stat.h>
36#include <time.h>
37#include <fcntl.h>
38#include <mntent.h>
39#include <stdlib.h>
40#include <signal.h>
41#include "mount.h"
42
43
44/* Updating mtab ----------------------------------------------*/
45
46/* Flag for already existing lock file. */
47static int we_created_lockfile = 0;
48static int lockfile_fd = -1;
49
50/* Flag to indicate that signals have been set up. */
51static int signals_have_been_setup = 0;
52
53static void
54handler (int sig) {
55 exit(EX_USER);
56}
57
58static void
59setlkw_timeout (int sig) {
60 /* nothing, fcntl will fail anyway */
61}
62
63/* Remove lock file. */
64void
65unlock_mtab (void) {
66 if (we_created_lockfile) {
67 close(lockfile_fd);
68 lockfile_fd = -1;
69 unlink (_PATH_MOUNTED_LOCK);
70 we_created_lockfile = 0;
71 }
72}
73
74/* Create the lock file.
75 The lock file will be removed if we catch a signal or when we exit. */
76/* The old code here used flock on a lock file /etc/mtab~ and deleted
77 this lock file afterwards. However, as rgooch remarks, that has a
78 race: a second mount may be waiting on the lock and proceed as
79 soon as the lock file is deleted by the first mount, and immediately
80 afterwards a third mount comes, creates a new /etc/mtab~, applies
81 flock to that, and also proceeds, so that the second and third mount
82 now both are scribbling in /etc/mtab.
83 The new code uses a link() instead of a creat(), where we proceed
84 only if it was us that created the lock, and hence we always have
85 to delete the lock afterwards. Now the use of flock() is in principle
86 superfluous, but avoids an arbitrary sleep(). */
87
88/* Where does the link point to? Obvious choices are mtab and mtab~~.
89 HJLu points out that the latter leads to races. Right now we use
90 mtab~.<pid> instead. Use 20 as upper bound for the length of %d. */
91#define MOUNTLOCK_LINKTARGET _PATH_MOUNTED_LOCK "%d"
92#define MOUNTLOCK_LINKTARGET_LTH (sizeof(_PATH_MOUNTED_LOCK)+20)
93
94/*
95 * The original mount locking code has used sleep(1) between attempts and
96 * maximal number of attemps has been 5.
97 *
98 * There was very small number of attempts and extremely long waiting (1s)
99 * that is useless on machines with large number of concurret mount processes.
100 *
101 * Now we wait few thousand microseconds between attempts and we have global
102 * time limit (30s) rather than limit for number of attempts. The advantage
103 * is that this method also counts time which we spend in fcntl(F_SETLKW) and
104 * number of attempts is not so much restricted.
105 *
106 * -- kzak@redhat.com [2007-Mar-2007]
107 */
108
109/* maximum seconds between first and last attempt */
110#define MOUNTLOCK_MAXTIME 30
111
112/* sleep time (in microseconds, max=999999) between attempts */
113#define MOUNTLOCK_WAITTIME 5000
114
115int
116lock_mtab (void) {
117 int i;
118 struct timespec waittime;
119 struct timeval maxtime;
120 char linktargetfile[MOUNTLOCK_LINKTARGET_LTH];
121
122 if (!signals_have_been_setup) {
123 int sig = 0;
124 struct sigaction sa;
125
126 sa.sa_handler = handler;
127 sa.sa_flags = 0;
128 sigfillset (&sa.sa_mask);
129
130 while (sigismember (&sa.sa_mask, ++sig) != -1
131 && sig != SIGCHLD) {
132 if (sig == SIGALRM)
133 sa.sa_handler = setlkw_timeout;
134 else
135 sa.sa_handler = handler;
136 sigaction (sig, &sa, (struct sigaction *) 0);
137 }
138 signals_have_been_setup = 1;
139 }
140
141 sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ());
142
143 i = open (linktargetfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
144 if (i < 0) {
145 /* linktargetfile does not exist (as a file)
146 and we cannot create it. Read-only filesystem?
147 Too many files open in the system?
148 Filesystem full? */
149 return EX_FILEIO;
150 }
151 close(i);
152
153 gettimeofday(&maxtime, NULL);
154 maxtime.tv_sec += MOUNTLOCK_MAXTIME;
155
156 waittime.tv_sec = 0;
157 waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
158
159 /* Repeat until it was us who made the link */
160 while (!we_created_lockfile) {
161 struct timeval now;
162 struct flock flock;
163 int errsv, j;
164
165 j = link(linktargetfile, _PATH_MOUNTED_LOCK);
166 errsv = errno;
167
168 if (j == 0)
169 we_created_lockfile = 1;
170
171 if (j < 0 && errsv != EEXIST) {
172 (void) unlink(linktargetfile);
173 return EX_FILEIO;
174 }
175
176 lockfile_fd = open (_PATH_MOUNTED_LOCK, O_WRONLY);
177
178 if (lockfile_fd < 0) {
179 /* Strange... Maybe the file was just deleted? */
180 gettimeofday(&now, NULL);
181 if (errno == ENOENT && now.tv_sec < maxtime.tv_sec) {
182 we_created_lockfile = 0;
183 continue;
184 }
185 (void) unlink(linktargetfile);
186 return EX_FILEIO;
187 }
188
189 flock.l_type = F_WRLCK;
190 flock.l_whence = SEEK_SET;
191 flock.l_start = 0;
192 flock.l_len = 0;
193
194 if (j == 0) {
195 /* We made the link. Now claim the lock. If we can't
196 * get it, continue anyway
197 */
198 fcntl (lockfile_fd, F_SETLK, &flock);
199 (void) unlink(linktargetfile);
200 } else {
201 /* Someone else made the link. Wait. */
202 gettimeofday(&now, NULL);
203 if (now.tv_sec < maxtime.tv_sec) {
204 alarm(maxtime.tv_sec - now.tv_sec);
205 if (fcntl (lockfile_fd, F_SETLKW, &flock) == -1) {
206 (void) unlink(linktargetfile);
207 return EX_FILEIO;
208 }
209 alarm(0);
210 nanosleep(&waittime, NULL);
211 } else {
212 (void) unlink(linktargetfile);
213 return EX_FILEIO;
214 }
215 close(lockfile_fd);
216 }
217 }
218 return 0;
219}
220
Note: See TracBrowser for help on using the repository browser.