int in_use;
unsigned short seq;
unsigned short seq_max;
- struct mutex mutex;
+ struct rw_semaphore rw_mutex;
struct idr ipcs_idr;
};
#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
-/* must be called with ids->mutex acquired.*/
+/* must be called with ids->rw_mutex acquired for writing */
int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
+
+/* must be called with ids->rw_mutex acquired for reading */
int ipc_get_maxid(struct ipc_ids *);
/* must be called with both locks acquired. */
void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
+/*
+ * ipc_lock_down: called with rw_mutex held
+ * ipc_lock: called without that lock held
+ */
+struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *, int);
struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
struct ipc_ops *, struct ipc_params *);
-static inline int ipc_buildid(struct ipc_ids *ids, int id, int seq)
+static inline int ipc_buildid(int id, int seq)
{
return SEQ_MULTIPLIER * seq + id;
}
/*
* Must be called with ipcp locked
*/
-static inline int ipc_checkid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp,
- int uid)
+static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid)
{
if (uid / SEQ_MULTIPLIER != ipcp->seq)
return 1;
rcu_read_unlock();
}
+static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids,
+ int id)
+{
+ struct kern_ipc_perm *out;
+
+ out = ipc_lock_down(ids, id);
+ if (IS_ERR(out))
+ return out;
+
+ if (ipc_checkid(out, id)) {
+ ipc_unlock(out);
+ return ERR_PTR(-EIDRM);
+ }
+
+ return out;
+}
+
static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids,
int id)
{
if (IS_ERR(out))
return out;
- if (ipc_checkid(ids, out, id)) {
+ if (ipc_checkid(out, id)) {
ipc_unlock(out);
return ERR_PTR(-EIDRM);
}