Fixups for l_pid
Subsystems (9)
v6 cover Fixups for l_pid
LTP fcntl tests (fcntl11 fcntl14 fcntl17 fcntl19 fcntl20 fcntl21) have been failing for NFSv4 mounts due to an unexpected l_pid. What follows are some fixups:
v2: - Rebase onto linux-next
- Revert back to using the stack in locks_mandatory_area(), and fixup patch description for 1/3
v3: - The lkp-robot found some serious per_thread_ops performance
regressions for v1 and v2, so this version changes things around to not acquire a reference to struct pid in fl_nspid for every lock. Instead, it drops fl_nspid altogether, and defers the lookup of the namespace-translated pid until it actually needed.
v4: - Instead of looking up the virtual pid by way of referencing the struct
task of the that pid, instead use find_pid_ns() and pid_nr_ns(), which avoids a the problem where we race to get a reference to the struct task while it may be freed.
v5: - Squash previous 2/3 and 3/3 to avoid regression where F_GETLK would
return the init_ns pid instead of a translated pid.
v6: - State clearly how the differing cases of l_pid translation should be
handled, specifically regarding remote locks on remote files: that fl_pid ought to be returned from the filesystem as <= 0 to indicate that it makes no sense to translate this l_pid.
- Follow up with a patch to have filesystems negate fl_pid for remote locks on remote files.
Benjamin Coddington (3):
fs/locks: Use allocation rather than the stack in fcntl_getlk() fs/locks: Remove fl_nspid and use fs-specific l_pid for remote locks staging/lustre, 9p, ceph, cifs, dlm: negate remote pids for F_GETLK
drivers/staging/lustre/lustre/ldlm/ldlm_flock.c | 2 +- fs/9p/vfs_file.c | 2 +- fs/ceph/locks.c | 2 +- fs/cifs/cifssmb.c | 2 +- fs/dlm/plock.c | 2 +- fs/fuse/file.c | 6 +- fs/locks.c | 108 ++++++++++++++---------- include/linux/fs.h | 2 +- 8 files changed, 72 insertions(+), 54 deletions(-)
Signature · 1 line
2.9.3
PATCH v6 1/3 fs/locks: Use allocation rather than the stack in fcntl_getlk()
Struct file_lock is fairly large, so let's save some space on the stack by using an allocation for struct file_lock in fcntl_getlk(), just as we do for fcntl_setlk().
--- fs/locks.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
fs/locks.c +26 -20
@@ -2086,14 +2086,17 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)*/ int fcntl_getlk (struct file *filp,unsigned int cmd,struct flock *flock) { -struct file_lock file_lock; +struct file_lock *fl;int error; + fl =locks_alloc_lock (); +if (fl ==NULL ) +return -ENOMEM ; error = -EINVAL ;if (flock->l_type !=F_RDLCK && flock->l_type !=F_WRLCK ) goto out; - error =flock_to_posix_lock (filp, &file_lock, flock); + error =flock_to_posix_lock (filp, fl, flock);if (error) goto out;
@@ -2103,23 +2106,22 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) goto out; cmd =F_GETLK ; - file_lock.fl_flags |=FL_OFDLCK ; - file_lock.fl_owner = filp; + fl->fl_flags |=FL_OFDLCK ; + fl->fl_owner = filp; } - error =vfs_test_lock (filp, &file_lock); + error =vfs_test_lock (filp, fl);if (error) goto out; - flock->l_type = file_lock.fl_type; -if (file_lock.fl_type !=F_UNLCK ) { - error =posix_lock_to_flock (flock, &file_lock); + flock->l_type = fl->fl_type; +if (fl->fl_type !=F_UNLCK ) { + error =posix_lock_to_flock (flock, fl);if (error) - goto rel_priv; + goto out; } -rel_priv: -locks_release_private (&file_lock); out: +locks_free_lock (fl);return error; }
@@ -2298,14 +2300,18 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,*/ int fcntl_getlk64 (struct file *filp,unsigned int cmd,struct flock64 *flock) { -struct file_lock file_lock; +struct file_lock *fl;int error; + fl =locks_alloc_lock (); +if (fl ==NULL ) +return -ENOMEM ; + error = -EINVAL ;if (flock->l_type !=F_RDLCK && flock->l_type !=F_WRLCK ) goto out; - error =flock64_to_posix_lock (filp, &file_lock, flock); + error =flock64_to_posix_lock (filp, fl, flock);if (error) goto out;
@@ -2315,20 +2321,20 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock) goto out; cmd =F_GETLK64 ; - file_lock.fl_flags |=FL_OFDLCK ; - file_lock.fl_owner = filp; + fl->fl_flags |=FL_OFDLCK ; + fl->fl_owner = filp; } - error =vfs_test_lock (filp, &file_lock); + error =vfs_test_lock (filp, fl);if (error) goto out; - flock->l_type = file_lock.fl_type; -if (file_lock.fl_type !=F_UNLCK ) -posix_lock_to_flock64 (flock, &file_lock); + flock->l_type = fl->fl_type; +if (fl->fl_type !=F_UNLCK ) +posix_lock_to_flock64 (flock, fl); -locks_release_private (&file_lock); out: +locks_free_lock (fl);return error; }
Signature · 1 line
2.9.3
PATCH v6 2/3 fs/locks: Remove fl_nspid and use fs-specific l_pid for remote locks
In reply to Benjamin CoddingtonSince commit c69899a17ca4 "NFSv4: Update of VFS byte range lock must be atomic with the stateid update", NFSv4 has been inserting locks in rpciod worker context. The result is that the file_lock's fl_nspid is the kworker's pid instead of the original userspace pid.
The fl_nspid is only used to represent the namespaced virtual pid number when displaying locks or returning from F_GETLK. There's no reason to set it for every inserted lock, since we can usually just look it up from fl_pid. So, instead of looking up and holding struct pid for every lock, let's just look up the virtual pid number from fl_pid when it is needed. That means we can remove fl_nspid entirely.
The translaton and presentation of fl_pid should handle the following four cases:
1 - F_GETLK on a remote file with a remote lock:
In this case, the filesystem should determine the l_pid to return here. Filesystems should indicate that the fl_pid represents a non-local pid value that should not be translated by returning an fl_pid <= 0.
2 - F_GETLK on a local file with a remote lock:
This should be the l_pid of the lock manager process, and translated.
3 - F_GETLK on a remote file with a local lock, and
4 - F_GETLK on a local file with a local lock:
These should be the translated l_pid of the local locking process.
Fuse was already doing the correct thing by translating the pid into the caller's namespace. With this change we must update fuse to translate to init's pid namespace, so that the locks API can then translate from init's pid namespace into the pid namespace of the caller.
--- fs/fuse/file.c | 6 +++--- fs/locks.c | 62 ++++++++++++++++++++++++++++++++---------------------- include/linux/fs.h | 2 +- 3 files changed, 41 insertions(+), 29 deletions(-)
fs/fuse/file.c +3 -3
@@ -2101,11 +2101,11 @@ static int convert_fuse_file_lock(struct fuse_conn *fc, fl->fl_end = ffl->end;/* -* Convert pid into the caller's pid namespace. If the pid -* does not map into the namespace fl_pid will get set to 0. +* Convert pid into init's pid namespace. The locks API will +* translate it into the caller's pid namespace. */ rcu_read_lock (); - fl->fl_pid =pid_vnr (find_pid_ns (ffl->pid, fc->pid_ns)); + fl->fl_pid =pid_nr_ns (find_pid_ns (ffl->pid, fc->pid_ns), &init_pid_ns);rcu_read_unlock ();break ;
fs/locks.c +37 -25
113 lines not on this page · raw message
include/linux/fs.h +1 -1
@@ -908,6 +908,7 @@ static inline struct file *get_file(struct file *f)#define FL_UNLOCK_PENDING 512/* Lease is being broken */ #define FL_OFDLCK 1024/* lock is "owned" by struct file */ #define FL_LAYOUT 2048/* outstanding pNFS layout */ +#define FL_PID_PRIV 4096/* F_GETLK should report fl_pid */ #define FL_CLOSE_POSIX (FL_POSIX | FL_CLOSE)
@@ -984,7 +985,6 @@ struct file_lock {unsigned char fl_type;unsigned int fl_pid;int fl_link_cpu;/* what cpu's list is this on? */ -struct pid *fl_nspid;wait_queue_head_t fl_wait;struct file *fl_file;loff_t fl_start;
Signature · 1 line
2.9.3
PATCH v6 3/3 staging/lustre, 9p, ceph, cifs, dlm: negate remote pids for F_GETLK
In reply to Benjamin CoddingtonIn the previous patch, the locks API will expect that if a filesystem returns a remote pid as opposed to a local pid for F_GETLK, that remote pid will be <= 0. This signifies that the pid is remote, and the locks API will forego translating that pid into the pid namespace of the local calling process. Since local pids will never be larger than PID_MAX_LIMIT (which is currently defined as <= 4 million), but pid_t is an unsigned int, we should have plenty of room to represent remote pids with negative numbers if we assume that remote pid numbers are similarly limited. If this is not the case, then we run the risk of having a remote pid returned for which there is also a corresponding local pid. This is a problem we have now, but this patch should reduce the chances of that occurring, while also returning those remote pid numbers, for whatever that may be worth.
This patch updates lustre, 9p, ceph, cifs, and dlm to negate the remote pid returned for F_GETLK lock requests.
--- drivers/staging/lustre/lustre/ldlm/ldlm_flock.c | 2 +- fs/9p/vfs_file.c | 2 +- fs/ceph/locks.c | 2 +- fs/cifs/cifssmb.c | 2 +- fs/dlm/plock.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-)
drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +1 -1
@@ -596,7 +596,7 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)default : getlk->fl_type =F_UNLCK ; } - getlk->fl_pid = (pid_t )lock->l_policy_data.l_flock.pid; + getlk->fl_pid = -(pid_t )lock->l_policy_data.l_flock.pid; getlk->fl_start = (loff_t )lock->l_policy_data.l_flock.start; getlk->fl_end = (loff_t )lock->l_policy_data.l_flock.end; }else {
fs/9p/vfs_file.c +1 -1
@@ -288,7 +288,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) fl->fl_end =OFFSET_MAX ; else fl->fl_end = glock.start + glock.length - 1; - fl->fl_pid = glock.proc_id; + fl->fl_pid = -glock.proc_id; }kfree (glock.client_id);return res;
fs/ceph/locks.c +1 -1
@@ -79,7 +79,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, err =ceph_mdsc_do_request (mdsc, inode, req);if (operation ==CEPH_MDS_OP_GETFILELOCK ) { - fl->fl_pid =le64_to_cpu (req->r_reply_info.filelock_reply->pid); + fl->fl_pid = -le64_to_cpu (req->r_reply_info.filelock_reply->pid);if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) fl->fl_type =F_RDLCK ;else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
fs/cifs/cifssmb.c +1 -1
@@ -2515,7 +2515,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pLockData->fl_start =le64_to_cpu (parm_data->start); pLockData->fl_end = pLockData->fl_start +le64_to_cpu (parm_data->length) -1 ; - pLockData->fl_pid =le32_to_cpu (parm_data->pid); + pLockData->fl_pid = -le32_to_cpu (parm_data->pid); } }
fs/dlm/plock.c +1 -1
@@ -367,7 +367,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,locks_init_lock (fl); fl->fl_type = (op->info.ex) ?F_WRLCK :F_RDLCK ; fl->fl_flags =FL_POSIX ; - fl->fl_pid = op->info.pid; + fl->fl_pid = -op->info.pid; fl->fl_start = op->info.start; fl->fl_end = op->info.end; rv =0 ;
Signature · 1 line
2.9.3
Re: [PATCH 3/3] staging/lustre, 9p, ceph, cifs, dlm: negate remote pids for F_GETLK
Quoted 82 lines · Benjamin Coddington
In the previous patch, the locks API will expect that if a filesystem returns a remote pid as opposed to a local pid for
F_GETLK, that remote pid will be <= 0. This signifies that the pid is remote, and the locks API will forego translating that pid into the pid namespace of the local calling process. Since local pids will never be larger thanPID_MAX_LIMIT(which is currently defined as <= 4 million), butpid_tis an unsigned int, we should have plenty of room to represent remote pids with negative numbers if we assume that remote pid numbers are similarly limited. If this is not the case, then we run the risk of having a remote pid returned for which there is also a corresponding local pid. This is a problem we have now, but this patch should reduce the chances of that occurring, while also returning those remote pid numbers, for whatever that may be worth.This patch updates lustre, 9p, ceph, cifs, and dlm to negate the remote pid returned for
F_GETLKlock requests.Signed-off-by Benjamin Coddington <[email protected]>--- drivers/staging/lustre/lustre/ldlm/ldlm_flock.c | 2 +- fs/9p/vfs_file.c | 2 +- fs/ceph/locks.c | 2 +- fs/cifs/cifssmb.c | 2 +- fs/dlm/plock.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-)drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +1
-1@@ -596,7 +596,7 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)default : getlk->fl_type =F_UNLCK ; } - getlk->fl_pid = (pid_t )lock->l_policy_data.l_flock.pid; + getlk->fl_pid = -(pid_t )lock->l_policy_data.l_flock.pid; getlk->fl_start = (loff_t )lock->l_policy_data.l_flock.start; getlk->fl_end = (loff_t )lock->l_policy_data.l_flock.end; }else {fs/9p/vfs_file.c +1
-1@@ -288,7 +288,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) fl->fl_end =OFFSET_MAX ; else fl->fl_end = glock.start + glock.length - 1; - fl->fl_pid = glock.proc_id; + fl->fl_pid = -glock.proc_id; }kfree (glock.client_id);return res;fs/ceph/locks.c +1
-1@@ -79,7 +79,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, err =ceph_mdsc_do_request (mdsc, inode, req);if (operation ==CEPH_MDS_OP_GETFILELOCK ) { - fl->fl_pid =le64_to_cpu (req->r_reply_info.filelock_reply->pid); + fl->fl_pid = -le64_to_cpu (req->r_reply_info.filelock_reply->pid);if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) fl->fl_type =F_RDLCK ;else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)fs/cifs/cifssmb.c +1
-1@@ -2515,7 +2515,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pLockData->fl_start =le64_to_cpu (parm_data->start); pLockData->fl_end = pLockData->fl_start +le64_to_cpu (parm_data->length) -1 ; - pLockData->fl_pid =le32_to_cpu (parm_data->pid); + pLockData->fl_pid = -le32_to_cpu (parm_data->pid); } }fs/dlm/plock.c +0
-0
fs/dlm/plock.c int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file, · line 373
Quoted 8 lines
fs/dlm/plock.c +1
-1@@ -367,7 +367,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,locks_init_lock (fl); fl->fl_type = (op->info.ex) ?F_WRLCK :F_RDLCK ; fl->fl_flags =FL_POSIX ; - fl->fl_pid = op->info.pid; + fl->fl_pid = -op->info.pid; fl->fl_start = op->info.start; fl->fl_end = op->info.end; rv =0 ;
I think this is probably a reasonable thing to do, given that we also report OFD locks today with an l_pid of -1. The pid on any sort of distributed fs is pretty meaningless anyway.
I think this all looks good. I'll plan to merge it for -next in a bit and do some testing with it.
Thanks!
Signature · 1 line
Jeff Layton <[email protected]>