Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
0004  */
0005 
0006 #include <linux/fs.h>
0007 #include <linux/miscdevice.h>
0008 #include <linux/poll.h>
0009 #include <linux/dlm.h>
0010 #include <linux/dlm_plock.h>
0011 #include <linux/slab.h>
0012 
0013 #include "dlm_internal.h"
0014 #include "lockspace.h"
0015 
0016 static DEFINE_SPINLOCK(ops_lock);
0017 static LIST_HEAD(send_list);
0018 static LIST_HEAD(recv_list);
0019 static DECLARE_WAIT_QUEUE_HEAD(send_wq);
0020 static DECLARE_WAIT_QUEUE_HEAD(recv_wq);
0021 
0022 struct plock_async_data {
0023     void *fl;
0024     void *file;
0025     struct file_lock flc;
0026     int (*callback)(struct file_lock *fl, int result);
0027 };
0028 
0029 struct plock_op {
0030     struct list_head list;
0031     int done;
0032     /* if lock op got interrupted while waiting dlm_controld reply */
0033     bool sigint;
0034     struct dlm_plock_info info;
0035     /* if set indicates async handling */
0036     struct plock_async_data *data;
0037 };
0038 
0039 static inline void set_version(struct dlm_plock_info *info)
0040 {
0041     info->version[0] = DLM_PLOCK_VERSION_MAJOR;
0042     info->version[1] = DLM_PLOCK_VERSION_MINOR;
0043     info->version[2] = DLM_PLOCK_VERSION_PATCH;
0044 }
0045 
0046 static int check_version(struct dlm_plock_info *info)
0047 {
0048     if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
0049         (DLM_PLOCK_VERSION_MINOR < info->version[1])) {
0050         log_print("plock device version mismatch: "
0051               "kernel (%u.%u.%u), user (%u.%u.%u)",
0052               DLM_PLOCK_VERSION_MAJOR,
0053               DLM_PLOCK_VERSION_MINOR,
0054               DLM_PLOCK_VERSION_PATCH,
0055               info->version[0],
0056               info->version[1],
0057               info->version[2]);
0058         return -EINVAL;
0059     }
0060     return 0;
0061 }
0062 
0063 static void dlm_release_plock_op(struct plock_op *op)
0064 {
0065     kfree(op->data);
0066     kfree(op);
0067 }
0068 
0069 static void send_op(struct plock_op *op)
0070 {
0071     set_version(&op->info);
0072     spin_lock(&ops_lock);
0073     list_add_tail(&op->list, &send_list);
0074     spin_unlock(&ops_lock);
0075     wake_up(&send_wq);
0076 }
0077 
0078 /* If a process was killed while waiting for the only plock on a file,
0079    locks_remove_posix will not see any lock on the file so it won't
0080    send an unlock-close to us to pass on to userspace to clean up the
0081    abandoned waiter.  So, we have to insert the unlock-close when the
0082    lock call is interrupted. */
0083 
0084 static void do_unlock_close(const struct dlm_plock_info *info)
0085 {
0086     struct plock_op *op;
0087 
0088     op = kzalloc(sizeof(*op), GFP_NOFS);
0089     if (!op)
0090         return;
0091 
0092     op->info.optype     = DLM_PLOCK_OP_UNLOCK;
0093     op->info.pid        = info->pid;
0094     op->info.fsid       = info->fsid;
0095     op->info.number     = info->number;
0096     op->info.start      = 0;
0097     op->info.end        = OFFSET_MAX;
0098     op->info.owner      = info->owner;
0099 
0100     op->info.flags |= DLM_PLOCK_FL_CLOSE;
0101     send_op(op);
0102 }
0103 
0104 int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0105            int cmd, struct file_lock *fl)
0106 {
0107     struct plock_async_data *op_data;
0108     struct dlm_ls *ls;
0109     struct plock_op *op;
0110     int rv;
0111 
0112     ls = dlm_find_lockspace_local(lockspace);
0113     if (!ls)
0114         return -EINVAL;
0115 
0116     op = kzalloc(sizeof(*op), GFP_NOFS);
0117     if (!op) {
0118         rv = -ENOMEM;
0119         goto out;
0120     }
0121 
0122     op->info.optype     = DLM_PLOCK_OP_LOCK;
0123     op->info.pid        = fl->fl_pid;
0124     op->info.ex     = (fl->fl_type == F_WRLCK);
0125     op->info.wait       = IS_SETLKW(cmd);
0126     op->info.fsid       = ls->ls_global_id;
0127     op->info.number     = number;
0128     op->info.start      = fl->fl_start;
0129     op->info.end        = fl->fl_end;
0130     /* async handling */
0131     if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
0132         op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
0133         if (!op_data) {
0134             dlm_release_plock_op(op);
0135             rv = -ENOMEM;
0136             goto out;
0137         }
0138 
0139         /* fl_owner is lockd which doesn't distinguish
0140            processes on the nfs client */
0141         op->info.owner  = (__u64) fl->fl_pid;
0142         op_data->callback = fl->fl_lmops->lm_grant;
0143         locks_init_lock(&op_data->flc);
0144         locks_copy_lock(&op_data->flc, fl);
0145         op_data->fl     = fl;
0146         op_data->file   = file;
0147 
0148         op->data = op_data;
0149 
0150         send_op(op);
0151         rv = FILE_LOCK_DEFERRED;
0152         goto out;
0153     } else {
0154         op->info.owner  = (__u64)(long) fl->fl_owner;
0155     }
0156 
0157     send_op(op);
0158 
0159     rv = wait_event_interruptible(recv_wq, (op->done != 0));
0160     if (rv == -ERESTARTSYS) {
0161         spin_lock(&ops_lock);
0162         /* recheck under ops_lock if we got a done != 0,
0163          * if so this interrupt case should be ignored
0164          */
0165         if (op->done != 0) {
0166             spin_unlock(&ops_lock);
0167             goto do_lock_wait;
0168         }
0169 
0170         op->sigint = true;
0171         spin_unlock(&ops_lock);
0172         log_debug(ls, "%s: wait interrupted %x %llx pid %d",
0173               __func__, ls->ls_global_id,
0174               (unsigned long long)number, op->info.pid);
0175         goto out;
0176     }
0177 
0178 do_lock_wait:
0179 
0180     WARN_ON(!list_empty(&op->list));
0181 
0182     rv = op->info.rv;
0183 
0184     if (!rv) {
0185         if (locks_lock_file_wait(file, fl) < 0)
0186             log_error(ls, "dlm_posix_lock: vfs lock error %llx",
0187                   (unsigned long long)number);
0188     }
0189 
0190     dlm_release_plock_op(op);
0191 out:
0192     dlm_put_lockspace(ls);
0193     return rv;
0194 }
0195 EXPORT_SYMBOL_GPL(dlm_posix_lock);
0196 
0197 /* Returns failure iff a successful lock operation should be canceled */
0198 static int dlm_plock_callback(struct plock_op *op)
0199 {
0200     struct plock_async_data *op_data = op->data;
0201     struct file *file;
0202     struct file_lock *fl;
0203     struct file_lock *flc;
0204     int (*notify)(struct file_lock *fl, int result) = NULL;
0205     int rv = 0;
0206 
0207     WARN_ON(!list_empty(&op->list));
0208 
0209     /* check if the following 2 are still valid or make a copy */
0210     file = op_data->file;
0211     flc = &op_data->flc;
0212     fl = op_data->fl;
0213     notify = op_data->callback;
0214 
0215     if (op->info.rv) {
0216         notify(fl, op->info.rv);
0217         goto out;
0218     }
0219 
0220     /* got fs lock; bookkeep locally as well: */
0221     flc->fl_flags &= ~FL_SLEEP;
0222     if (posix_lock_file(file, flc, NULL)) {
0223         /*
0224          * This can only happen in the case of kmalloc() failure.
0225          * The filesystem's own lock is the authoritative lock,
0226          * so a failure to get the lock locally is not a disaster.
0227          * As long as the fs cannot reliably cancel locks (especially
0228          * in a low-memory situation), we're better off ignoring
0229          * this failure than trying to recover.
0230          */
0231         log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
0232               (unsigned long long)op->info.number, file, fl);
0233     }
0234 
0235     rv = notify(fl, 0);
0236     if (rv) {
0237         /* XXX: We need to cancel the fs lock here: */
0238         log_print("dlm_plock_callback: lock granted after lock request "
0239               "failed; dangling lock!\n");
0240         goto out;
0241     }
0242 
0243 out:
0244     dlm_release_plock_op(op);
0245     return rv;
0246 }
0247 
0248 int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0249              struct file_lock *fl)
0250 {
0251     struct dlm_ls *ls;
0252     struct plock_op *op;
0253     int rv;
0254     unsigned char fl_flags = fl->fl_flags;
0255 
0256     ls = dlm_find_lockspace_local(lockspace);
0257     if (!ls)
0258         return -EINVAL;
0259 
0260     op = kzalloc(sizeof(*op), GFP_NOFS);
0261     if (!op) {
0262         rv = -ENOMEM;
0263         goto out;
0264     }
0265 
0266     /* cause the vfs unlock to return ENOENT if lock is not found */
0267     fl->fl_flags |= FL_EXISTS;
0268 
0269     rv = locks_lock_file_wait(file, fl);
0270     if (rv == -ENOENT) {
0271         rv = 0;
0272         goto out_free;
0273     }
0274     if (rv < 0) {
0275         log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx",
0276               rv, (unsigned long long)number);
0277     }
0278 
0279     op->info.optype     = DLM_PLOCK_OP_UNLOCK;
0280     op->info.pid        = fl->fl_pid;
0281     op->info.fsid       = ls->ls_global_id;
0282     op->info.number     = number;
0283     op->info.start      = fl->fl_start;
0284     op->info.end        = fl->fl_end;
0285     if (fl->fl_lmops && fl->fl_lmops->lm_grant)
0286         op->info.owner  = (__u64) fl->fl_pid;
0287     else
0288         op->info.owner  = (__u64)(long) fl->fl_owner;
0289 
0290     if (fl->fl_flags & FL_CLOSE) {
0291         op->info.flags |= DLM_PLOCK_FL_CLOSE;
0292         send_op(op);
0293         rv = 0;
0294         goto out;
0295     }
0296 
0297     send_op(op);
0298     wait_event(recv_wq, (op->done != 0));
0299 
0300     WARN_ON(!list_empty(&op->list));
0301 
0302     rv = op->info.rv;
0303 
0304     if (rv == -ENOENT)
0305         rv = 0;
0306 
0307 out_free:
0308     dlm_release_plock_op(op);
0309 out:
0310     dlm_put_lockspace(ls);
0311     fl->fl_flags = fl_flags;
0312     return rv;
0313 }
0314 EXPORT_SYMBOL_GPL(dlm_posix_unlock);
0315 
0316 int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0317           struct file_lock *fl)
0318 {
0319     struct dlm_ls *ls;
0320     struct plock_op *op;
0321     int rv;
0322 
0323     ls = dlm_find_lockspace_local(lockspace);
0324     if (!ls)
0325         return -EINVAL;
0326 
0327     op = kzalloc(sizeof(*op), GFP_NOFS);
0328     if (!op) {
0329         rv = -ENOMEM;
0330         goto out;
0331     }
0332 
0333     op->info.optype     = DLM_PLOCK_OP_GET;
0334     op->info.pid        = fl->fl_pid;
0335     op->info.ex     = (fl->fl_type == F_WRLCK);
0336     op->info.fsid       = ls->ls_global_id;
0337     op->info.number     = number;
0338     op->info.start      = fl->fl_start;
0339     op->info.end        = fl->fl_end;
0340     if (fl->fl_lmops && fl->fl_lmops->lm_grant)
0341         op->info.owner  = (__u64) fl->fl_pid;
0342     else
0343         op->info.owner  = (__u64)(long) fl->fl_owner;
0344 
0345     send_op(op);
0346     wait_event(recv_wq, (op->done != 0));
0347 
0348     WARN_ON(!list_empty(&op->list));
0349 
0350     /* info.rv from userspace is 1 for conflict, 0 for no-conflict,
0351        -ENOENT if there are no locks on the file */
0352 
0353     rv = op->info.rv;
0354 
0355     fl->fl_type = F_UNLCK;
0356     if (rv == -ENOENT)
0357         rv = 0;
0358     else if (rv > 0) {
0359         locks_init_lock(fl);
0360         fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
0361         fl->fl_flags = FL_POSIX;
0362         fl->fl_pid = -op->info.pid;
0363         fl->fl_start = op->info.start;
0364         fl->fl_end = op->info.end;
0365         rv = 0;
0366     }
0367 
0368     dlm_release_plock_op(op);
0369 out:
0370     dlm_put_lockspace(ls);
0371     return rv;
0372 }
0373 EXPORT_SYMBOL_GPL(dlm_posix_get);
0374 
0375 /* a read copies out one plock request from the send list */
0376 static ssize_t dev_read(struct file *file, char __user *u, size_t count,
0377             loff_t *ppos)
0378 {
0379     struct dlm_plock_info info;
0380     struct plock_op *op = NULL;
0381 
0382     if (count < sizeof(info))
0383         return -EINVAL;
0384 
0385     spin_lock(&ops_lock);
0386     if (!list_empty(&send_list)) {
0387         op = list_first_entry(&send_list, struct plock_op, list);
0388         if (op->info.flags & DLM_PLOCK_FL_CLOSE)
0389             list_del(&op->list);
0390         else
0391             list_move(&op->list, &recv_list);
0392         memcpy(&info, &op->info, sizeof(info));
0393     }
0394     spin_unlock(&ops_lock);
0395 
0396     if (!op)
0397         return -EAGAIN;
0398 
0399     /* there is no need to get a reply from userspace for unlocks
0400        that were generated by the vfs cleaning up for a close
0401        (the process did not make an unlock call). */
0402 
0403     if (op->info.flags & DLM_PLOCK_FL_CLOSE)
0404         dlm_release_plock_op(op);
0405 
0406     if (copy_to_user(u, &info, sizeof(info)))
0407         return -EFAULT;
0408     return sizeof(info);
0409 }
0410 
0411 /* a write copies in one plock result that should match a plock_op
0412    on the recv list */
0413 static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
0414              loff_t *ppos)
0415 {
0416     struct plock_op *op = NULL, *iter;
0417     struct dlm_plock_info info;
0418     int do_callback = 0;
0419 
0420     if (count != sizeof(info))
0421         return -EINVAL;
0422 
0423     if (copy_from_user(&info, u, sizeof(info)))
0424         return -EFAULT;
0425 
0426     if (check_version(&info))
0427         return -EINVAL;
0428 
0429     spin_lock(&ops_lock);
0430     list_for_each_entry(iter, &recv_list, list) {
0431         if (iter->info.fsid == info.fsid &&
0432             iter->info.number == info.number &&
0433             iter->info.owner == info.owner) {
0434             if (iter->sigint) {
0435                 list_del(&iter->list);
0436                 spin_unlock(&ops_lock);
0437 
0438                 pr_debug("%s: sigint cleanup %x %llx pid %d",
0439                       __func__, iter->info.fsid,
0440                       (unsigned long long)iter->info.number,
0441                       iter->info.pid);
0442                 do_unlock_close(&iter->info);
0443                 memcpy(&iter->info, &info, sizeof(info));
0444                 dlm_release_plock_op(iter);
0445                 return count;
0446             }
0447             list_del_init(&iter->list);
0448             memcpy(&iter->info, &info, sizeof(info));
0449             if (iter->data)
0450                 do_callback = 1;
0451             else
0452                 iter->done = 1;
0453             op = iter;
0454             break;
0455         }
0456     }
0457     spin_unlock(&ops_lock);
0458 
0459     if (op) {
0460         if (do_callback)
0461             dlm_plock_callback(op);
0462         else
0463             wake_up(&recv_wq);
0464     } else
0465         log_print("%s: no op %x %llx", __func__,
0466               info.fsid, (unsigned long long)info.number);
0467     return count;
0468 }
0469 
0470 static __poll_t dev_poll(struct file *file, poll_table *wait)
0471 {
0472     __poll_t mask = 0;
0473 
0474     poll_wait(file, &send_wq, wait);
0475 
0476     spin_lock(&ops_lock);
0477     if (!list_empty(&send_list))
0478         mask = EPOLLIN | EPOLLRDNORM;
0479     spin_unlock(&ops_lock);
0480 
0481     return mask;
0482 }
0483 
0484 static const struct file_operations dev_fops = {
0485     .read    = dev_read,
0486     .write   = dev_write,
0487     .poll    = dev_poll,
0488     .owner   = THIS_MODULE,
0489     .llseek  = noop_llseek,
0490 };
0491 
0492 static struct miscdevice plock_dev_misc = {
0493     .minor = MISC_DYNAMIC_MINOR,
0494     .name = DLM_PLOCK_MISC_NAME,
0495     .fops = &dev_fops
0496 };
0497 
0498 int dlm_plock_init(void)
0499 {
0500     int rv;
0501 
0502     rv = misc_register(&plock_dev_misc);
0503     if (rv)
0504         log_print("dlm_plock_init: misc_register failed %d", rv);
0505     return rv;
0506 }
0507 
0508 void dlm_plock_exit(void)
0509 {
0510     misc_deregister(&plock_dev_misc);
0511 }
0512