aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c223
1 files changed, 140 insertions, 83 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 96b33989147d..3b0d05dcd7c1 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -133,6 +133,20 @@
133#define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) 133#define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK)
134#define IS_LEASE(fl) (fl->fl_flags & FL_LEASE) 134#define IS_LEASE(fl) (fl->fl_flags & FL_LEASE)
135 135
136static bool lease_breaking(struct file_lock *fl)
137{
138 return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
139}
140
141static int target_leasetype(struct file_lock *fl)
142{
143 if (fl->fl_flags & FL_UNLOCK_PENDING)
144 return F_UNLCK;
145 if (fl->fl_flags & FL_DOWNGRADE_PENDING)
146 return F_RDLCK;
147 return fl->fl_type;
148}
149
136int leases_enable = 1; 150int leases_enable = 1;
137int lease_break_time = 45; 151int lease_break_time = 45;
138 152
@@ -1119,6 +1133,17 @@ int locks_mandatory_area(int read_write, struct inode *inode,
1119 1133
1120EXPORT_SYMBOL(locks_mandatory_area); 1134EXPORT_SYMBOL(locks_mandatory_area);
1121 1135
1136static void lease_clear_pending(struct file_lock *fl, int arg)
1137{
1138 switch (arg) {
1139 case F_UNLCK:
1140 fl->fl_flags &= ~FL_UNLOCK_PENDING;
1141 /* fall through: */
1142 case F_RDLCK:
1143 fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
1144 }
1145}
1146
1122/* We already had a lease on this file; just change its type */ 1147/* We already had a lease on this file; just change its type */
1123int lease_modify(struct file_lock **before, int arg) 1148int lease_modify(struct file_lock **before, int arg)
1124{ 1149{
@@ -1127,6 +1152,7 @@ int lease_modify(struct file_lock **before, int arg)
1127 1152
1128 if (error) 1153 if (error)
1129 return error; 1154 return error;
1155 lease_clear_pending(fl, arg);
1130 locks_wake_up_blocks(fl); 1156 locks_wake_up_blocks(fl);
1131 if (arg == F_UNLCK) 1157 if (arg == F_UNLCK)
1132 locks_delete_lock(before); 1158 locks_delete_lock(before);
@@ -1135,19 +1161,25 @@ int lease_modify(struct file_lock **before, int arg)
1135 1161
1136EXPORT_SYMBOL(lease_modify); 1162EXPORT_SYMBOL(lease_modify);
1137 1163
1164static bool past_time(unsigned long then)
1165{
1166 if (!then)
1167 /* 0 is a special value meaning "this never expires": */
1168 return false;
1169 return time_after(jiffies, then);
1170}
1171
1138static void time_out_leases(struct inode *inode) 1172static void time_out_leases(struct inode *inode)
1139{ 1173{
1140 struct file_lock **before; 1174 struct file_lock **before;
1141 struct file_lock *fl; 1175 struct file_lock *fl;
1142 1176
1143 before = &inode->i_flock; 1177 before = &inode->i_flock;
1144 while ((fl = *before) && IS_LEASE(fl) && (fl->fl_type & F_INPROGRESS)) { 1178 while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
1145 if ((fl->fl_break_time == 0) 1179 if (past_time(fl->fl_downgrade_time))
1146 || time_before(jiffies, fl->fl_break_time)) { 1180 lease_modify(before, F_RDLCK);
1147 before = &fl->fl_next; 1181 if (past_time(fl->fl_break_time))
1148 continue; 1182 lease_modify(before, F_UNLCK);
1149 }
1150 lease_modify(before, fl->fl_type & ~F_INPROGRESS);
1151 if (fl == *before) /* lease_modify may have freed fl */ 1183 if (fl == *before) /* lease_modify may have freed fl */
1152 before = &fl->fl_next; 1184 before = &fl->fl_next;
1153 } 1185 }
@@ -1165,7 +1197,7 @@ static void time_out_leases(struct inode *inode)
1165 */ 1197 */
1166int __break_lease(struct inode *inode, unsigned int mode) 1198int __break_lease(struct inode *inode, unsigned int mode)
1167{ 1199{
1168 int error = 0, future; 1200 int error = 0;
1169 struct file_lock *new_fl, *flock; 1201 struct file_lock *new_fl, *flock;
1170 struct file_lock *fl; 1202 struct file_lock *fl;
1171 unsigned long break_time; 1203 unsigned long break_time;
@@ -1182,24 +1214,13 @@ int __break_lease(struct inode *inode, unsigned int mode)
1182 if ((flock == NULL) || !IS_LEASE(flock)) 1214 if ((flock == NULL) || !IS_LEASE(flock))
1183 goto out; 1215 goto out;
1184 1216
1217 if (!locks_conflict(flock, new_fl))
1218 goto out;
1219
1185 for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) 1220 for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next)
1186 if (fl->fl_owner == current->files) 1221 if (fl->fl_owner == current->files)
1187 i_have_this_lease = 1; 1222 i_have_this_lease = 1;
1188 1223
1189 if (want_write) {
1190 /* If we want write access, we have to revoke any lease. */
1191 future = F_UNLCK | F_INPROGRESS;
1192 } else if (flock->fl_type & F_INPROGRESS) {
1193 /* If the lease is already being broken, we just leave it */
1194 future = flock->fl_type;
1195 } else if (flock->fl_type & F_WRLCK) {
1196 /* Downgrade the exclusive lease to a read-only lease. */
1197 future = F_RDLCK | F_INPROGRESS;
1198 } else {
1199 /* the existing lease was read-only, so we can read too. */
1200 goto out;
1201 }
1202
1203 if (IS_ERR(new_fl) && !i_have_this_lease 1224 if (IS_ERR(new_fl) && !i_have_this_lease
1204 && ((mode & O_NONBLOCK) == 0)) { 1225 && ((mode & O_NONBLOCK) == 0)) {
1205 error = PTR_ERR(new_fl); 1226 error = PTR_ERR(new_fl);
@@ -1214,12 +1235,18 @@ int __break_lease(struct inode *inode, unsigned int mode)
1214 } 1235 }
1215 1236
1216 for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { 1237 for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
1217 if (fl->fl_type != future) { 1238 if (want_write) {
1218 fl->fl_type = future; 1239 if (fl->fl_flags & FL_UNLOCK_PENDING)
1240 continue;
1241 fl->fl_flags |= FL_UNLOCK_PENDING;
1219 fl->fl_break_time = break_time; 1242 fl->fl_break_time = break_time;
1220 /* lease must have lmops break callback */ 1243 } else {
1221 fl->fl_lmops->lm_break(fl); 1244 if (lease_breaking(flock))
1245 continue;
1246 fl->fl_flags |= FL_DOWNGRADE_PENDING;
1247 fl->fl_downgrade_time = break_time;
1222 } 1248 }
1249 fl->fl_lmops->lm_break(fl);
1223 } 1250 }
1224 1251
1225 if (i_have_this_lease || (mode & O_NONBLOCK)) { 1252 if (i_have_this_lease || (mode & O_NONBLOCK)) {
@@ -1243,10 +1270,13 @@ restart:
1243 if (error >= 0) { 1270 if (error >= 0) {
1244 if (error == 0) 1271 if (error == 0)
1245 time_out_leases(inode); 1272 time_out_leases(inode);
1246 /* Wait for the next lease that has not been broken yet */ 1273 /*
1274 * Wait for the next conflicting lease that has not been
1275 * broken yet
1276 */
1247 for (flock = inode->i_flock; flock && IS_LEASE(flock); 1277 for (flock = inode->i_flock; flock && IS_LEASE(flock);
1248 flock = flock->fl_next) { 1278 flock = flock->fl_next) {
1249 if (flock->fl_type & F_INPROGRESS) 1279 if (locks_conflict(new_fl, flock))
1250 goto restart; 1280 goto restart;
1251 } 1281 }
1252 error = 0; 1282 error = 0;
@@ -1314,7 +1344,7 @@ int fcntl_getlease(struct file *filp)
1314 for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl); 1344 for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
1315 fl = fl->fl_next) { 1345 fl = fl->fl_next) {
1316 if (fl->fl_file == filp) { 1346 if (fl->fl_file == filp) {
1317 type = fl->fl_type & ~F_INPROGRESS; 1347 type = target_leasetype(fl);
1318 break; 1348 break;
1319 } 1349 }
1320 } 1350 }
@@ -1322,50 +1352,23 @@ int fcntl_getlease(struct file *filp)
1322 return type; 1352 return type;
1323} 1353}
1324 1354
1325/** 1355int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
1326 * generic_setlease - sets a lease on an open file
1327 * @filp: file pointer
1328 * @arg: type of lease to obtain
1329 * @flp: input - file_lock to use, output - file_lock inserted
1330 *
1331 * The (input) flp->fl_lmops->lm_break function is required
1332 * by break_lease().
1333 *
1334 * Called with file_lock_lock held.
1335 */
1336int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1337{ 1356{
1338 struct file_lock *fl, **before, **my_before = NULL, *lease; 1357 struct file_lock *fl, **before, **my_before = NULL, *lease;
1339 struct dentry *dentry = filp->f_path.dentry; 1358 struct dentry *dentry = filp->f_path.dentry;
1340 struct inode *inode = dentry->d_inode; 1359 struct inode *inode = dentry->d_inode;
1341 int error, rdlease_count = 0, wrlease_count = 0; 1360 int error;
1342 1361
1343 lease = *flp; 1362 lease = *flp;
1344 1363
1345 error = -EACCES; 1364 error = -EAGAIN;
1346 if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) 1365 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
1347 goto out;
1348 error = -EINVAL;
1349 if (!S_ISREG(inode->i_mode))
1350 goto out; 1366 goto out;
1351 error = security_file_lock(filp, arg); 1367 if ((arg == F_WRLCK)
1352 if (error) 1368 && ((dentry->d_count > 1)
1369 || (atomic_read(&inode->i_count) > 1)))
1353 goto out; 1370 goto out;
1354 1371
1355 time_out_leases(inode);
1356
1357 BUG_ON(!(*flp)->fl_lmops->lm_break);
1358
1359 if (arg != F_UNLCK) {
1360 error = -EAGAIN;
1361 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
1362 goto out;
1363 if ((arg == F_WRLCK)
1364 && ((dentry->d_count > 1)
1365 || (atomic_read(&inode->i_count) > 1)))
1366 goto out;
1367 }
1368
1369 /* 1372 /*
1370 * At this point, we know that if there is an exclusive 1373 * At this point, we know that if there is an exclusive
1371 * lease on this file, then we hold it on this filp 1374 * lease on this file, then we hold it on this filp
@@ -1374,27 +1377,28 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1374 * then the file is not open by anyone (including us) 1377 * then the file is not open by anyone (including us)
1375 * except for this filp. 1378 * except for this filp.
1376 */ 1379 */
1380 error = -EAGAIN;
1377 for (before = &inode->i_flock; 1381 for (before = &inode->i_flock;
1378 ((fl = *before) != NULL) && IS_LEASE(fl); 1382 ((fl = *before) != NULL) && IS_LEASE(fl);
1379 before = &fl->fl_next) { 1383 before = &fl->fl_next) {
1380 if (fl->fl_file == filp) 1384 if (fl->fl_file == filp) {
1381 my_before = before; 1385 my_before = before;
1382 else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) 1386 continue;
1383 /* 1387 }
1384 * Someone is in the process of opening this 1388 /*
1385 * file for writing so we may not take an 1389 * No exclusive leases if someone else has a lease on
1386 * exclusive lease on it. 1390 * this file:
1387 */ 1391 */
1388 wrlease_count++; 1392 if (arg == F_WRLCK)
1389 else 1393 goto out;
1390 rdlease_count++; 1394 /*
1395 * Modifying our existing lease is OK, but no getting a
1396 * new lease if someone else is opening for write:
1397 */
1398 if (fl->fl_flags & FL_UNLOCK_PENDING)
1399 goto out;
1391 } 1400 }
1392 1401
1393 error = -EAGAIN;
1394 if ((arg == F_RDLCK && (wrlease_count > 0)) ||
1395 (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
1396 goto out;
1397
1398 if (my_before != NULL) { 1402 if (my_before != NULL) {
1399 error = lease->fl_lmops->lm_change(my_before, arg); 1403 error = lease->fl_lmops->lm_change(my_before, arg);
1400 if (!error) 1404 if (!error)
@@ -1402,9 +1406,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1402 goto out; 1406 goto out;
1403 } 1407 }
1404 1408
1405 if (arg == F_UNLCK)
1406 goto out;
1407
1408 error = -EINVAL; 1409 error = -EINVAL;
1409 if (!leases_enable) 1410 if (!leases_enable)
1410 goto out; 1411 goto out;
@@ -1415,6 +1416,62 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1415out: 1416out:
1416 return error; 1417 return error;
1417} 1418}
1419
1420int generic_delete_lease(struct file *filp, struct file_lock **flp)
1421{
1422 struct file_lock *fl, **before;
1423 struct dentry *dentry = filp->f_path.dentry;
1424 struct inode *inode = dentry->d_inode;
1425
1426 for (before = &inode->i_flock;
1427 ((fl = *before) != NULL) && IS_LEASE(fl);
1428 before = &fl->fl_next) {
1429 if (fl->fl_file != filp)
1430 continue;
1431 return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
1432 }
1433 return -EAGAIN;
1434}
1435
1436/**
1437 * generic_setlease - sets a lease on an open file
1438 * @filp: file pointer
1439 * @arg: type of lease to obtain
1440 * @flp: input - file_lock to use, output - file_lock inserted
1441 *
1442 * The (input) flp->fl_lmops->lm_break function is required
1443 * by break_lease().
1444 *
1445 * Called with file_lock_lock held.
1446 */
1447int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1448{
1449 struct dentry *dentry = filp->f_path.dentry;
1450 struct inode *inode = dentry->d_inode;
1451 int error;
1452
1453 if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
1454 return -EACCES;
1455 if (!S_ISREG(inode->i_mode))
1456 return -EINVAL;
1457 error = security_file_lock(filp, arg);
1458 if (error)
1459 return error;
1460
1461 time_out_leases(inode);
1462
1463 BUG_ON(!(*flp)->fl_lmops->lm_break);
1464
1465 switch (arg) {
1466 case F_UNLCK:
1467 return generic_delete_lease(filp, flp);
1468 case F_RDLCK:
1469 case F_WRLCK:
1470 return generic_add_lease(filp, arg, flp);
1471 default:
1472 BUG();
1473 }
1474}
1418EXPORT_SYMBOL(generic_setlease); 1475EXPORT_SYMBOL(generic_setlease);
1419 1476
1420static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) 1477static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
@@ -2126,7 +2183,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
2126 } 2183 }
2127 } else if (IS_LEASE(fl)) { 2184 } else if (IS_LEASE(fl)) {
2128 seq_printf(f, "LEASE "); 2185 seq_printf(f, "LEASE ");
2129 if (fl->fl_type & F_INPROGRESS) 2186 if (lease_breaking(fl))
2130 seq_printf(f, "BREAKING "); 2187 seq_printf(f, "BREAKING ");
2131 else if (fl->fl_file) 2188 else if (fl->fl_file)
2132 seq_printf(f, "ACTIVE "); 2189 seq_printf(f, "ACTIVE ");
@@ -2142,7 +2199,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
2142 : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); 2199 : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
2143 } else { 2200 } else {
2144 seq_printf(f, "%s ", 2201 seq_printf(f, "%s ",
2145 (fl->fl_type & F_INPROGRESS) 2202 (lease_breaking(fl))
2146 ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " 2203 ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
2147 : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); 2204 : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
2148 } 2205 }