|
@@ -180,16 +180,33 @@ static inline struct shmid_kernel *shm_obtain_object_check(struct ipc_namespace
|
|
|
*/
|
|
|
static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
|
|
|
{
|
|
|
- struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
|
|
|
+ struct kern_ipc_perm *ipcp;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ ipcp = ipc_obtain_object_idr(&shm_ids(ns), id);
|
|
|
+ if (IS_ERR(ipcp))
|
|
|
+ goto err;
|
|
|
|
|
|
+ ipc_lock_object(ipcp);
|
|
|
+ /*
|
|
|
+ * ipc_rmid() may have already freed the ID while ipc_lock_object()
|
|
|
+ * was spinning: here verify that the structure is still valid.
|
|
|
+ * Upon races with RMID, return -EIDRM, thus indicating that
|
|
|
+ * the ID points to a removed identifier.
|
|
|
+ */
|
|
|
+ if (ipc_valid_object(ipcp)) {
|
|
|
+ /* return a locked ipc object upon success */
|
|
|
+ return container_of(ipcp, struct shmid_kernel, shm_perm);
|
|
|
+ }
|
|
|
+
|
|
|
+ ipc_unlock_object(ipcp);
|
|
|
+err:
|
|
|
+ rcu_read_unlock();
|
|
|
/*
|
|
|
* Callers of shm_lock() must validate the status of the returned ipc
|
|
|
- * object pointer (as returned by ipc_lock()), and error out as
|
|
|
- * appropriate.
|
|
|
+ * object pointer and error out as appropriate.
|
|
|
*/
|
|
|
- if (IS_ERR(ipcp))
|
|
|
- return (void *)ipcp;
|
|
|
- return container_of(ipcp, struct shmid_kernel, shm_perm);
|
|
|
+ return (void *)ipcp;
|
|
|
}
|
|
|
|
|
|
static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
|