Skip to content

Commit 3210bcf

Browse files
Ian Kenthnaz
Ian Kent
authored andcommitted
vfs: make may_umount_tree() mount propagation aware
Now that autofs has namespace aware mounted checks the expire needs changes to make it aware of mount propagation. When checking for expiration may_umount_tree() checks only if the given mount is in use. This leads to a callback to the automount daemon to umount the mount which will fail if any propagated mounts are in use. To avoid this unnecessary call back may_umount_tree() needs to check propagated mount trees also. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ian Kent <[email protected]> Cc: Al Viro <[email protected]> Cc: Eric W. Biederman <[email protected]> Cc: Omar Sandoval <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 4954626 commit 3210bcf

File tree

4 files changed

+66
-13
lines changed

4 files changed

+66
-13
lines changed

fs/autofs4/expire.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
5252
goto done;
5353
}
5454

55-
/* Update the expiry counter if fs is busy */
55+
/* Update the expiry counter if fs is busy in any namespace */
5656
if (!may_umount_tree(path.mnt)) {
5757
struct autofs_info *ino;
5858

@@ -191,7 +191,7 @@ static int autofs4_direct_busy(struct vfsmount *mnt,
191191
{
192192
pr_debug("top %p %pd\n", top, top);
193193

194-
/* If it's busy update the expiry counters */
194+
/* If it's busy in any namespace update the expiry counters */
195195
if (!may_umount_tree(mnt)) {
196196
struct autofs_info *ino;
197197

fs/namespace.c

+62-9
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,33 @@ const struct seq_operations mounts_op = {
13101310
};
13111311
#endif /* CONFIG_PROC_FS */
13121312

1313+
struct mnt_tree_refs {
1314+
struct mount *root;
1315+
unsigned int refs;
1316+
unsigned int min_refs;
1317+
};
1318+
1319+
static void mnt_get_tree_refs(struct mnt_tree_refs *mtr)
1320+
{
1321+
struct mount *mnt = mtr->root;
1322+
struct mount *p;
1323+
1324+
/*
1325+
* Each propagated tree contribues 2 * #mounts - 1 to
1326+
* the minimal reference count. But when a mount is
1327+
* umounted and connected the mount doesn't hold a
1328+
* reference to its parent so it contributes a single
1329+
* reference.
1330+
*/
1331+
for (p = mnt; p; p = next_mnt(p, mnt)) {
1332+
mtr->refs += mnt_get_count(p);
1333+
if (p == mnt || p->mnt.mnt_flags & MNT_UMOUNT)
1334+
mtr->min_refs++;
1335+
else
1336+
mtr->min_refs += 2;
1337+
}
1338+
}
1339+
13131340
/**
13141341
* may_umount_tree - check if a mount tree is busy
13151342
* @mnt: root of mount tree
@@ -1321,25 +1348,51 @@ const struct seq_operations mounts_op = {
13211348
int may_umount_tree(struct vfsmount *m)
13221349
{
13231350
struct mount *mnt = real_mount(m);
1324-
int actual_refs = 0;
1325-
int minimum_refs = 0;
1326-
struct mount *p;
1351+
struct mount *parent = mnt->mnt_parent;
1352+
struct mnt_tree_refs mtr;
1353+
struct mount *p, *child;
1354+
13271355
BUG_ON(!m);
13281356

1329-
/* write lock needed for mnt_get_count */
1357+
down_read(&namespace_sem);
13301358
lock_mount_hash();
1331-
for (p = mnt; p; p = next_mnt(p, mnt)) {
1332-
actual_refs += mnt_get_count(p);
1333-
minimum_refs += 2;
1359+
1360+
mtr.root = mnt;
1361+
mtr.refs = 0;
1362+
mtr.min_refs = 0;
1363+
1364+
mnt_get_tree_refs(&mtr);
1365+
/*
1366+
* Caller holds a mount reference so minimum references
1367+
* to the tree at mnt is one greater than the minumum
1368+
* references.
1369+
*/
1370+
mtr.min_refs++;
1371+
1372+
/* The pnode.c propagation_next() function (as used below)
1373+
* returns each mount propogated from a given mount. Using
1374+
* the parent of mnt and matching the mnt->mnt_mountpoint
1375+
* gets the list of mounts propogated from mnt. To work
1376+
* out if the tree is in use (eg. open file or pwd) the
1377+
* reference counts of each of these mounts needs to be
1378+
* checked as well as mnt itself.
1379+
*/
1380+
for (p = propagation_next(parent, parent); p;
1381+
p = propagation_next(p, parent)) {
1382+
child = __lookup_mnt_last(&p->mnt, mnt->mnt_mountpoint);
1383+
if (child) {
1384+
mtr.root = child;
1385+
mnt_get_tree_refs(&mtr);
1386+
}
13341387
}
13351388
unlock_mount_hash();
1389+
up_read(&namespace_sem);
13361390

1337-
if (actual_refs > minimum_refs)
1391+
if (mtr.refs > mtr.min_refs)
13381392
return 0;
13391393

13401394
return 1;
13411395
}
1342-
13431396
EXPORT_SYMBOL(may_umount_tree);
13441397

13451398
/**

fs/pnode.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ void change_mnt_propagation(struct mount *mnt, int type)
143143
* vfsmount found while iterating with propagation_next() is
144144
* a peer of one we'd found earlier.
145145
*/
146-
static struct mount *propagation_next(struct mount *m,
147-
struct mount *origin)
146+
struct mount *propagation_next(struct mount *m, struct mount *origin)
148147
{
149148
/* are there any slaves of this mount? */
150149
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))

fs/pnode.h

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static inline void set_mnt_shared(struct mount *mnt)
3838
mnt->mnt.mnt_flags |= MNT_SHARED;
3939
}
4040

41+
struct mount *propagation_next(struct mount *, struct mount *);
4142
void change_mnt_propagation(struct mount *, int);
4243
int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
4344
struct hlist_head *);

0 commit comments

Comments
 (0)